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}
}
+
+
+ Cancel
+
+ {saving ? 'Saving…' : 'Save'}
+
+
+
+
+ );
+}
+
Object.assign(window, { Upload, Recorders, Capture, Monitors, Schedule, YouTubeImport });