diff --git a/services/capture/src/capture-manager.js b/services/capture/src/capture-manager.js index 5ab6e93..b89316b 100644 --- a/services/capture/src/capture-manager.js +++ b/services/capture/src/capture-manager.js @@ -139,6 +139,16 @@ const VIDEO_CODECS = { bitrateControl: true, pixFmt: 'p010le', }, + // XDCAM HD422 (MPEG-2 422) — the broadcast-standard codec for MXF OP1a. + // Used both in growing-files mode (via raw2bmx, which reads elementary + // MPEG-2 422 essence FIFOs) and in finalized MXF recordings (ffmpeg muxer). + // `-dc 10` + CBR bitrate (operator target, default 50M) match XDCAM HD422 + // essence. Short GOP (-g 15, -bf 2) keeps edit-friendly structure. + xdcam_hd422: { + args: ['-c:v', 'mpeg2video', '-pix_fmt', 'yuv422p', '-dc', '10', '-g', '15', '-bf', '2'], + bitrateControl: true, + pixFmt: 'yuv422p', + }, }; // nvenc codecs available in the capture image. Used both to validate the master diff --git a/services/premiere-plugin/js/main.js b/services/premiere-plugin/js/main.js index 0d1a22f..3dd2bd6 100644 --- a/services/premiere-plugin/js/main.js +++ b/services/premiere-plugin/js/main.js @@ -1979,12 +1979,13 @@ function importFileToPremiereProject(filePath) { '(function() {', ' var result = { success: false, message: "" };', ' try {', - ' var lf = new File("C:/Users/Administrator/Documents/df-import-log.txt");', - ' var opened = lf.open("a");', - ' result.message = "opened=" + opened + " fsName=" + lf.fsName + " err=" + (lf.error || "none");', - ' if (opened) { lf.writeln((new Date()).toString() + " v1.2.5 noop probe"); lf.close(); }', - ' /* keep success=false so the message surfaces in the panel popup */', - ' } catch (e) { result.message = "caught: " + e.message; }', + ' if (!app.project) { result.message = "No active Premiere Pro project"; return JSON.stringify(result); }', + ' var f = new File("' + safePath + '");', + ' if (!f.exists) { result.message = "File does not exist: ' + safePath + '"; return JSON.stringify(result); }', + ' app.project.importFiles(["' + safePath + '"], true);', + ' result.success = true;', + ' result.message = "File imported successfully";', + ' } catch (e) { result.message = "Error importing file: " + e.message; }', ' return JSON.stringify(result);', '})();', ].join('\n'); diff --git a/services/web-ui/public/modal-new-recorder.jsx b/services/web-ui/public/modal-new-recorder.jsx index e3eeffe..bb52d88 100644 --- a/services/web-ui/public/modal-new-recorder.jsx +++ b/services/web-ui/public/modal-new-recorder.jsx @@ -156,9 +156,9 @@ function NewRecorderModal({ open, onClose }) { const [recBitrate, setRecBitrate] = React.useState('25'); // Container is derived from the codec, not manually chosen: HEVC/ProRes/DNxHR // → MOV (fragmented, growing-capable); H.264 → MP4. - const recContainer = (recCodec === 'h264' || recCodec === 'h264_nvenc' || recCodec === 'libx264') ? 'mp4' : 'mov'; + const recContainer = (recCodec === 'h264' || recCodec === 'h264_nvenc' || recCodec === 'libx264') ? 'mp4' : (recCodec === 'xdcam_hd422' ? 'mxf' : 'mov'); // Codecs whose bitrate is operator-controlled (everything except ProRes). - const BITRATE_CODECS = new Set(['hevc_nvenc', 'h264_nvenc', 'libx264', 'libx265', 'dnxhd', 'dnxhr_hq']); + const BITRATE_CODECS = new Set(['hevc_nvenc', 'h264_nvenc', 'libx264', 'libx265', 'dnxhd', 'dnxhr_hq', 'xdcam_hd422']); const codecUsesBitrate = BITRATE_CODECS.has(recCodec); const [proxyOn, setProxyOn] = React.useState(true); const [growingOn, setGrowingOn] = React.useState(false); @@ -416,9 +416,10 @@ function NewRecorderModal({ open, onClose }) { H.264 → MP4), and master audio is always PCM (valid in MOV). */}
{[ - { id: 'hevc', label: 'HEVC Master (MOV)', codec: 'hevc_nvenc', bitrate: '25' }, - { id: 'h264', label: 'H.264 Proxy-friendly (MP4)', codec: 'h264_nvenc', bitrate: '25' }, - { id: 'dnxhr', label: 'DNxHR HQ (MOV)', codec: 'dnxhr_hq', bitrate: '145' }, + { id: 'hevc', label: 'HEVC Master (MOV)', codec: 'hevc_nvenc', bitrate: '25' }, + { id: 'h264', label: 'H.264 Proxy-friendly (MP4)', codec: 'h264_nvenc', bitrate: '25' }, + { id: 'xdcam', label: 'XDCAM HD422 (MXF OP1a)', codec: 'xdcam_hd422', bitrate: '50' }, + { id: 'dnxhr', label: 'DNxHR HQ (MOV)', codec: 'dnxhr_hq', bitrate: '145' }, ].map(p => ( } +
+ {configOpen && ( + setConfigOpen(false)} + onSaved={() => { setConfigOpen(false); onRefresh(); }} + /> + )} ); } @@ -2334,4 +2378,103 @@ function NewScheduleModal({ recorders, onClose, onCreated, defaultStart, default ); } +/* ===== Recorder Config Editor ===== */ +function RecorderConfigModal({ recorder, onClose, onSaved }) { + const [codec, setCodec] = React.useState(recorder.recording_codec || 'hevc_nvenc'); + const [bitrate, setBitrate] = React.useState(() => { + const raw = recorder.recording_video_bitrate || ''; + const m = String(raw).match(/^(\d+(?:\.\d+)?)/); + return m ? m[1] : '25'; + }); + const [growingOn, setGrowingOn] = React.useState(!!recorder.growing_enabled); + const [saving, setSaving] = React.useState(false); + const [err, setErr] = React.useState(null); + + const BITRATE_CODECS = new Set(['hevc_nvenc', 'h264_nvenc', 'libx264', 'libx265', 'dnxhd', 'dnxhr_hq', 'xdcam_hd422']); + const codecUsesBitrate = BITRATE_CODECS.has(codec); + const showBitrate = codecUsesBitrate || growingOn; + const container = (codec === 'h264' || codec === 'h264_nvenc' || codec === 'libx264') ? 'mp4' : (codec === 'xdcam_hd422' ? 'mxf' : 'mov'); + + const save = async () => { + setSaving(true); + setErr(null); + const body = { + recording_codec: codec, + recording_container: container, + growing_enabled: growingOn, + }; + if ((codecUsesBitrate || growingOn) && bitrate) { + body.recording_video_bitrate = `${bitrate}M`; + } + try { + const res = await window.ZAMPP_API.fetch('/recorders/' + recorder.id, { method: 'PATCH', body: JSON.stringify(body) }); + if (res && res.error) { setErr(res.error); setSaving(false); return; } + onSaved(); + } catch (e) { + setErr(e.message || 'Save failed'); + setSaving(false); + } + }; + + return ( +
+
e.stopPropagation()}> +
+
+
Edit recorder
+
{recorder.name}
+
+ +
+
+
+ + +
+ {showBitrate && ( +
+ + setBitrate(e.target.value)} /> +
+ )} +
+ +
+ Wraps XDCAM HD422 in MXF OP1a with periodic index updates so editors can import the file mid-record. +
+
+ {err &&
{err}
} +
+
+ + +
+
+
+ ); +} + Object.assign(window, { Upload, Recorders, Capture, Monitors, Schedule, YouTubeImport });