1#![forbid(unsafe_code)]
31
32pub mod math;
33
34pub mod ar_overlay;
35pub mod background_plate;
36pub mod camera_frustum;
37pub mod camera_rig;
38pub mod camera_tracker;
39pub mod camera_tracking;
40pub mod color;
41pub mod color_temp_control;
42pub mod constants;
43pub mod core_interop;
44pub mod dmx_scene;
45pub mod examples;
46pub mod frustum;
47pub mod frustum_culling;
48pub mod genlock;
49pub mod greenscreen;
50pub mod hdri_capture;
51pub mod icvfx;
52pub mod keying;
53pub mod led;
54pub mod led_volume;
55pub mod led_wall;
56pub mod lens;
57pub mod lens_projection;
58pub mod light_rig;
59pub mod metrics;
60pub mod mocap;
61pub mod motion_path;
62pub mod multicam;
63pub mod ndi_bridge;
64pub mod panel_topology;
65pub mod pixel_mapping;
66pub mod pixel_mapping_lut;
67pub mod preview;
68pub mod previz;
69pub mod projection_map;
70pub mod remote_session;
71pub mod render_layer;
72pub mod render_output;
73pub mod rig_path;
74pub mod scene;
75pub mod scene_setup;
76pub mod set_extension;
77pub mod stage;
78pub mod stage_element_layout;
79pub mod stage_layout;
80pub mod stage_manager;
81pub mod stage_safety;
82pub mod stage_visualization;
83pub mod sync;
84pub mod talent_keying;
85pub mod talent_tracking;
86pub mod timecode;
89pub mod tracking;
90pub mod tracking_data;
91pub mod tracking_filter;
95pub mod tracking_session;
96pub mod unreal;
97pub mod utils;
98pub mod virtual_set;
99pub mod virtual_studio;
100pub mod volume_calibration;
101pub mod workflows;
102
103use std::time::Duration;
104use thiserror::Error;
105
106#[derive(Debug, Error)]
108pub enum VirtualProductionError {
109 #[error("Camera tracking error: {0}")]
110 CameraTracking(String),
111
112 #[error("LED wall error: {0}")]
113 LedWall(String),
114
115 #[error("Calibration error: {0}")]
116 Calibration(String),
117
118 #[error("Synchronization error: {0}")]
119 Sync(String),
120
121 #[error("Color pipeline error: {0}")]
122 Color(String),
123
124 #[error("Motion capture error: {0}")]
125 MotionCapture(String),
126
127 #[error("Compositing error: {0}")]
128 Compositing(String),
129
130 #[error("Unreal integration error: {0}")]
131 UnrealIntegration(String),
132
133 #[error("Multi-camera error: {0}")]
134 MultiCamera(String),
135
136 #[error("Frame timing error: expected {expected:?}, got {actual:?}")]
137 FrameTiming {
138 expected: Duration,
139 actual: Duration,
140 },
141
142 #[error("Invalid configuration: {0}")]
143 InvalidConfig(String),
144}
145
146pub type Result<T> = std::result::Result<T, VirtualProductionError>;
147
148#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
150pub enum WorkflowType {
151 LedWall,
153 Hybrid,
155 GreenScreen,
157 AugmentedReality,
159}
160
161#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
163pub enum QualityMode {
164 Draft,
166 Preview,
168 Final,
170}
171
172#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
174pub struct VirtualProductionConfig {
175 pub workflow: WorkflowType,
177 pub target_fps: f64,
179 pub sync_accuracy_ms: f64,
181 pub quality: QualityMode,
183 pub color_calibration: bool,
185 pub lens_correction: bool,
187 pub num_cameras: usize,
189 pub motion_capture: bool,
191 pub unreal_integration: bool,
193}
194
195impl Default for VirtualProductionConfig {
196 fn default() -> Self {
197 Self {
198 workflow: WorkflowType::LedWall,
199 target_fps: 60.0,
200 sync_accuracy_ms: 0.5,
201 quality: QualityMode::Preview,
202 color_calibration: true,
203 lens_correction: true,
204 num_cameras: 1,
205 motion_capture: false,
206 unreal_integration: false,
207 }
208 }
209}
210
211impl VirtualProductionConfig {
212 #[must_use]
214 pub fn with_workflow(mut self, workflow: WorkflowType) -> Self {
215 self.workflow = workflow;
216 self
217 }
218
219 #[must_use]
221 pub fn with_target_fps(mut self, fps: f64) -> Self {
222 self.target_fps = fps;
223 self
224 }
225
226 #[must_use]
228 pub fn with_sync_accuracy_ms(mut self, accuracy: f64) -> Self {
229 self.sync_accuracy_ms = accuracy;
230 self
231 }
232
233 #[must_use]
235 pub fn with_quality(mut self, quality: QualityMode) -> Self {
236 self.quality = quality;
237 self
238 }
239
240 #[must_use]
242 pub fn with_num_cameras(mut self, num: usize) -> Self {
243 self.num_cameras = num;
244 self
245 }
246}
247
248pub struct VirtualProduction {
250 config: VirtualProductionConfig,
251 camera_tracker: tracking::camera::CameraTracker,
252 led_renderer: led::render::LedRenderer,
253 compositor: icvfx::composite::IcvfxCompositor,
254 color_pipeline: color::pipeline::ColorPipeline,
255 genlock: sync::genlock::GenlockSync,
256 multicam_manager: Option<multicam::manager::MultiCameraManager>,
257}
258
259impl VirtualProduction {
260 pub fn new(config: VirtualProductionConfig) -> Result<Self> {
262 let camera_tracker =
263 tracking::camera::CameraTracker::new(tracking::camera::CameraTrackerConfig::default())?;
264
265 let led_renderer =
266 led::render::LedRenderer::new(led::render::LedRendererConfig::default())?;
267
268 let compositor =
269 icvfx::composite::IcvfxCompositor::new(icvfx::composite::CompositorConfig::default())?;
270
271 let color_pipeline =
272 color::pipeline::ColorPipeline::new(color::pipeline::ColorPipelineConfig::default())?;
273
274 let genlock = sync::genlock::GenlockSync::new(sync::genlock::GenlockConfig::default())?;
275
276 let multicam_manager = if config.num_cameras > 1 {
277 Some(multicam::manager::MultiCameraManager::new(
278 multicam::manager::MultiCameraConfig {
279 num_cameras: config.num_cameras,
280 auto_switch: false,
281 },
282 )?)
283 } else {
284 None
285 };
286
287 Ok(Self {
288 config,
289 camera_tracker,
290 led_renderer,
291 compositor,
292 color_pipeline,
293 genlock,
294 multicam_manager,
295 })
296 }
297
298 #[must_use]
300 pub fn config(&self) -> &VirtualProductionConfig {
301 &self.config
302 }
303
304 #[must_use]
306 pub fn camera_tracker(&self) -> &tracking::camera::CameraTracker {
307 &self.camera_tracker
308 }
309
310 pub fn camera_tracker_mut(&mut self) -> &mut tracking::camera::CameraTracker {
312 &mut self.camera_tracker
313 }
314
315 #[must_use]
317 pub fn led_renderer(&self) -> &led::render::LedRenderer {
318 &self.led_renderer
319 }
320
321 pub fn led_renderer_mut(&mut self) -> &mut led::render::LedRenderer {
323 &mut self.led_renderer
324 }
325
326 #[must_use]
328 pub fn compositor(&self) -> &icvfx::composite::IcvfxCompositor {
329 &self.compositor
330 }
331
332 pub fn compositor_mut(&mut self) -> &mut icvfx::composite::IcvfxCompositor {
334 &mut self.compositor
335 }
336
337 pub fn set_compositor_resolution(&mut self, width: usize, height: usize) -> Result<()> {
341 let config = icvfx::composite::CompositorConfig {
342 resolution: (width, height),
343 ..self.compositor.config().clone()
344 };
345 self.compositor = icvfx::composite::IcvfxCompositor::new(config)?;
346 Ok(())
347 }
348
349 #[must_use]
351 pub fn color_pipeline(&self) -> &color::pipeline::ColorPipeline {
352 &self.color_pipeline
353 }
354
355 pub fn color_pipeline_mut(&mut self) -> &mut color::pipeline::ColorPipeline {
357 &mut self.color_pipeline
358 }
359
360 #[must_use]
362 pub fn genlock(&self) -> &sync::genlock::GenlockSync {
363 &self.genlock
364 }
365
366 #[must_use]
368 pub fn multicam_manager(&self) -> Option<&multicam::manager::MultiCameraManager> {
369 self.multicam_manager.as_ref()
370 }
371}
372
373#[cfg(test)]
374mod tests {
375 use super::*;
376
377 #[test]
378 fn test_config_default() {
379 let config = VirtualProductionConfig::default();
380 assert_eq!(config.workflow, WorkflowType::LedWall);
381 assert_eq!(config.target_fps, 60.0);
382 assert_eq!(config.sync_accuracy_ms, 0.5);
383 assert_eq!(config.quality, QualityMode::Preview);
384 }
385
386 #[test]
387 fn test_config_builder() {
388 let config = VirtualProductionConfig::default()
389 .with_workflow(WorkflowType::Hybrid)
390 .with_target_fps(120.0)
391 .with_quality(QualityMode::Final)
392 .with_num_cameras(4);
393
394 assert_eq!(config.workflow, WorkflowType::Hybrid);
395 assert_eq!(config.target_fps, 120.0);
396 assert_eq!(config.quality, QualityMode::Final);
397 assert_eq!(config.num_cameras, 4);
398 }
399
400 #[test]
401 fn test_virtual_production_creation() {
402 let config = VirtualProductionConfig::default();
403 let vp = VirtualProduction::new(config);
404 assert!(vp.is_ok());
405 }
406
407 #[test]
408 fn test_multicam_manager_creation() {
409 let config = VirtualProductionConfig::default().with_num_cameras(4);
410 let vp = VirtualProduction::new(config).expect("should succeed in test");
411 assert!(vp.multicam_manager().is_some());
412 }
413}