Skip to main content

vmix_core/
models.rs

1use serde::{Deserialize, Serialize};
2
3#[cfg(not(feature = "std"))]
4use alloc::{string::String, vec::Vec};
5
6#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
7pub struct Vmix {
8    #[serde(rename = "version")]
9    pub version: String,
10
11    #[serde(rename = "edition")]
12    pub edition: String,
13
14    #[serde(rename = "preset", default)]
15    pub preset: Option<String>,
16
17    #[serde(rename = "inputs")]
18    pub inputs: Inputs,
19
20    #[serde(rename = "outputs", default)]
21    pub outputs: Option<Outputs>,
22
23    #[serde(rename = "overlays")]
24    pub overlays: Overlays,
25
26    #[serde(rename = "preview")]
27    pub preview: String,
28
29    #[serde(rename = "active")]
30    pub active: String,
31
32    #[serde(rename = "fadeToBlack", with = "xml_bool")]
33    pub fade_to_black: bool,
34
35    #[serde(rename = "transitions")]
36    pub transitions: Transitions,
37
38    #[serde(rename = "recording", with = "xml_bool")]
39    pub recording: bool,
40
41    #[serde(rename = "external", with = "xml_bool")]
42    pub external: bool,
43
44    #[serde(rename = "streaming", with = "xml_bool")]
45    pub streaming: bool,
46
47    #[serde(rename = "playList", with = "xml_bool")]
48    pub play_list: bool,
49
50    #[serde(rename = "multiCorder", with = "xml_bool")]
51    pub multi_corder: bool,
52
53    #[serde(rename = "fullscreen", with = "xml_bool")]
54    pub fullscreen: bool,
55
56    #[serde(rename = "mix", default)]
57    pub mix: Vec<Mix>,
58
59    #[serde(rename = "audio")]
60    pub audio: Audio,
61
62    #[serde(rename = "dynamic")]
63    pub dynamic: Dynamic,
64}
65
66#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
67pub struct Audio {
68    #[serde(rename = "master")]
69    pub master: AudioBus,
70
71    #[serde(rename = "busA", default)]
72    pub bus_a: Option<AudioBus>,
73
74    #[serde(rename = "busB", default)]
75    pub bus_b: Option<AudioBus>,
76
77    #[serde(rename = "busC", default)]
78    pub bus_c: Option<AudioBus>,
79
80    #[serde(rename = "busD", default)]
81    pub bus_d: Option<AudioBus>,
82
83    #[serde(rename = "busE", default)]
84    pub bus_e: Option<AudioBus>,
85
86    #[serde(rename = "busF", default)]
87    pub bus_f: Option<AudioBus>,
88
89    #[serde(rename = "busG", default)]
90    pub bus_g: Option<AudioBus>,
91}
92
93#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
94pub struct AudioBus {
95    #[serde(rename = "@volume")]
96    pub volume: f64,
97
98    #[serde(rename = "@muted", with = "xml_bool")]
99    pub muted: bool,
100
101    #[serde(rename = "@meterF1")]
102    pub meter_f1: f64,
103
104    #[serde(rename = "@meterF2")]
105    pub meter_f2: f64,
106
107    #[serde(rename = "@headphonesVolume", default)]
108    pub headphones_volume: Option<f64>,
109
110    #[serde(rename = "@solo", default, with = "xml_bool_option")]
111    pub solo: Option<bool>,
112
113    #[serde(rename = "@sendToMaster", default, with = "xml_bool_option")]
114    pub send_to_master: Option<bool>,
115}
116
117#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
118pub struct Dynamic {
119    #[serde(rename = "input1")]
120    pub input1: String,
121
122    #[serde(rename = "input2")]
123    pub input2: String,
124
125    #[serde(rename = "input3")]
126    pub input3: String,
127
128    #[serde(rename = "input4")]
129    pub input4: String,
130
131    #[serde(rename = "value1")]
132    pub value1: String,
133
134    #[serde(rename = "value2")]
135    pub value2: String,
136
137    #[serde(rename = "value3")]
138    pub value3: String,
139
140    #[serde(rename = "value4")]
141    pub value4: String,
142}
143
144#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
145pub struct Inputs {
146    #[serde(rename = "input")]
147    pub input: Vec<Input>,
148}
149
150#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
151pub struct Input {
152    // 属性
153    #[serde(rename = "@key")]
154    pub key: String,
155
156    #[serde(rename = "@number")]
157    pub number: String,
158
159    #[serde(rename = "@type")]
160    pub input_type: String,
161
162    #[serde(rename = "@title")]
163    pub title: String,
164
165    #[serde(rename = "@shortTitle")]
166    pub short_title: String,
167
168    #[serde(rename = "@state")]
169    pub state: State,
170
171    #[serde(rename = "@position")]
172    pub position: String,
173
174    #[serde(rename = "@duration")]
175    pub duration: String,
176
177    #[serde(rename = "@loop", with = "xml_bool")]
178    pub input_loop: bool,
179
180    #[serde(rename = "@muted", default, with = "xml_bool_option")]
181    pub muted: Option<bool>,
182
183    #[serde(rename = "@volume", default)]
184    pub volume: Option<f64>,
185
186    #[serde(rename = "@balance", default)]
187    pub balance: Option<f64>,
188
189    #[serde(rename = "@solo", default, with = "xml_bool_option")]
190    pub solo: Option<bool>,
191
192    #[serde(rename = "@soloPFL", default, with = "xml_bool_option")]
193    pub solo_pfl: Option<bool>,
194
195    #[serde(rename = "@audiobusses", default)]
196    pub audiobusses: Option<String>,
197
198    #[serde(rename = "@meterF1", default)]
199    pub meter_f1: Option<f64>,
200
201    #[serde(rename = "@meterF2", default)]
202    pub meter_f2: Option<f64>,
203
204    #[serde(rename = "@gainDb", default)]
205    pub gain_db: Option<f64>,
206
207    #[serde(rename = "@selectedIndex", default)]
208    pub selected_index: Option<String>,
209
210    #[serde(rename = "@preset", default)]
211    pub preset: Option<String>,
212
213    // 子要素
214    #[serde(rename = "list", default)]
215    pub list: Option<List>,
216
217    #[serde(rename = "image", default)]
218    pub image: Vec<Image>,
219
220    #[serde(rename = "replay", default)]
221    pub replay: Option<Replay>,
222
223    #[serde(rename = "overlay", default)]
224    pub overlay: Vec<InputOverlay>,
225
226    #[serde(rename = "crop", default)]
227    pub crop: Option<Crop>,
228
229    #[serde(rename = "position", default)]
230    pub input_position: Option<Position>,
231}
232
233#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
234pub struct Image {
235    #[serde(rename = "index", default)]
236    pub index: Option<String>,
237
238    #[serde(rename = "name", default)]
239    pub name: Option<String>,
240}
241
242#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
243pub struct List {
244    #[serde(rename = "item", default)]
245    pub item: Vec<ListItem>,
246}
247
248#[derive(Serialize, Deserialize, Debug, Clone)]
249pub struct ItemClass {
250    #[serde(rename = "_selected")]
251    pub selected: String,
252}
253
254#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
255pub struct InputOverlay {
256    #[serde(rename = "@index")]
257    pub index: String,
258
259    #[serde(rename = "@key")]
260    pub key: String,
261
262    #[serde(rename = "position", default)]
263    pub position: Option<Position>,
264}
265
266#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
267pub struct Position {
268    #[serde(rename = "@panX", default)]
269    pub pan_x: Option<String>,
270
271    #[serde(rename = "@panY", default)]
272    pub pan_y: Option<String>,
273
274    #[serde(rename = "@zoomX", default)]
275    pub zoom_x: Option<String>,
276
277    #[serde(rename = "@zoomY", default)]
278    pub zoom_y: Option<String>,
279
280    #[serde(rename = "@x", default)]
281    pub x: Option<String>,
282
283    #[serde(rename = "@y", default)]
284    pub y: Option<String>,
285
286    #[serde(rename = "@width", default)]
287    pub width: Option<String>,
288
289    #[serde(rename = "@height", default)]
290    pub height: Option<String>,
291}
292
293#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
294pub struct Replay {
295    // 子要素
296    #[serde(rename = "timecode", default)]
297    pub timecode: String,
298
299    #[serde(rename = "timecodeA", default)]
300    pub timecode_a: String,
301
302    #[serde(rename = "timecodeB", default)]
303    pub timecode_b: String,
304
305    // 属性
306    #[serde(rename = "@live", default)]
307    pub live: Option<String>,
308
309    #[serde(rename = "@recording", default)]
310    pub recording: Option<String>,
311
312    #[serde(rename = "@channelMode", default)]
313    pub channel_mode: String,
314
315    #[serde(rename = "@events", default)]
316    pub events: String,
317
318    #[serde(rename = "@eventsA", default)]
319    pub events_a: String,
320
321    #[serde(rename = "@eventsB", default)]
322    pub events_b: String,
323
324    #[serde(rename = "@cameraA", default)]
325    pub camera_a: String,
326
327    #[serde(rename = "@cameraB", default)]
328    pub camera_b: String,
329
330    #[serde(rename = "@speed", default)]
331    pub speed: String,
332
333    #[serde(rename = "@speedA", default)]
334    pub speed_a: String,
335
336    #[serde(rename = "@speedB", default)]
337    pub speed_b: String,
338}
339
340#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
341pub struct Overlays {
342    #[serde(rename = "overlay")]
343    pub overlay: Vec<OverlaysOverlay>,
344}
345
346#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
347pub struct OverlaysOverlay {
348    #[serde(rename = "@number")]
349    pub number: String,
350}
351
352#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
353pub struct Transitions {
354    #[serde(rename = "transition")]
355    pub transition: Vec<Transition>,
356}
357
358#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
359pub struct Transition {
360    #[serde(rename = "@number")]
361    pub number: String,
362
363    #[serde(rename = "@effect")]
364    pub effect: String,
365
366    #[serde(rename = "@duration")]
367    pub duration: String,
368}
369
370#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
371pub struct ListItem {
372    #[serde(rename = "@enabled", default)]
373    pub enabled: Option<String>,
374    #[serde(rename = "@selected", default)]
375    pub selected: Option<String>,
376    #[serde(rename = "@index", default)]
377    pub index: Option<String>,
378    #[serde(rename = "$value", default)]
379    pub text: Option<String>,
380}
381
382// Custom deserializer for XML boolean values
383mod xml_bool {
384    use serde::{Deserialize, Deserializer, Serializer};
385
386    #[cfg(not(feature = "std"))]
387    use alloc::{format, string::String};
388
389    pub fn serialize<S>(value: &bool, serializer: S) -> Result<S::Ok, S::Error>
390    where
391        S: Serializer,
392    {
393        let s = if *value { "True" } else { "False" };
394        serializer.serialize_str(s)
395    }
396
397    pub fn deserialize<'de, D>(deserializer: D) -> Result<bool, D::Error>
398    where
399        D: Deserializer<'de>,
400    {
401        let s = String::deserialize(deserializer)?;
402        match s.as_str() {
403            "True" => Ok(true),
404            "False" => Ok(false),
405            _ => Err(serde::de::Error::custom(format!(
406                "Invalid boolean value: {}",
407                s
408            ))),
409        }
410    }
411}
412
413// Custom deserializer for optional XML boolean values
414mod xml_bool_option {
415    use serde::{Deserialize, Deserializer, Serializer};
416
417    #[cfg(not(feature = "std"))]
418    use alloc::{format, string::String};
419
420    pub fn serialize<S>(value: &Option<bool>, serializer: S) -> Result<S::Ok, S::Error>
421    where
422        S: Serializer,
423    {
424        match value {
425            Some(b) => {
426                let s = if *b { "True" } else { "False" };
427                serializer.serialize_str(s)
428            }
429            None => serializer.serialize_none(),
430        }
431    }
432
433    pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<bool>, D::Error>
434    where
435        D: Deserializer<'de>,
436    {
437        let opt = Option::<String>::deserialize(deserializer)?;
438        match opt {
439            Some(s) => match s.as_str() {
440                "True" => Ok(Some(true)),
441                "False" => Ok(Some(false)),
442                _ => Err(serde::de::Error::custom(format!(
443                    "Invalid boolean value: {}",
444                    s
445                ))),
446            },
447            None => Ok(None),
448        }
449    }
450}
451
452// Outputs structure
453#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
454pub struct Outputs {
455    #[serde(rename = "output", default)]
456    pub output: Vec<Output>,
457}
458
459#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
460pub struct Output {
461    #[serde(rename = "@type")]
462    pub output_type: String,
463    #[serde(rename = "@number")]
464    pub number: String,
465    #[serde(rename = "@source")]
466    pub source: String,
467    #[serde(rename = "@external", default)]
468    pub external: Option<String>,
469    #[serde(rename = "@ndi", default)]
470    pub ndi: Option<String>,
471    #[serde(rename = "@mix", default)]
472    pub mix: Option<String>,
473    #[serde(rename = "@inputNumber", default)]
474    pub input_number: Option<String>,
475}
476
477// Mix structure
478#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
479pub struct Mix {
480    #[serde(rename = "@number")]
481    pub number: String,
482    #[serde(rename = "preview")]
483    pub preview: String,
484    #[serde(rename = "active")]
485    pub active: String,
486}
487
488// Crop structure for inputs
489#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
490pub struct Crop {
491    #[serde(rename = "@X1")]
492    pub x1: String,
493    #[serde(rename = "@Y1")]
494    pub y1: String,
495    #[serde(rename = "@X2")]
496    pub x2: String,
497    #[serde(rename = "@Y2")]
498    pub y2: String,
499}
500
501#[derive(Serialize, Deserialize, Debug, Clone)]
502pub enum Audiobusses {
503    #[serde(rename = "M")]
504    M,
505
506    #[serde(rename = "A")]
507    A,
508
509    #[serde(rename = "B")]
510    B,
511
512    #[serde(rename = "C")]
513    C,
514
515    #[serde(rename = "D")]
516    D,
517
518    #[serde(rename = "E")]
519    E,
520
521    #[serde(rename = "F")]
522    F,
523
524    #[serde(rename = "G")]
525    G,
526}
527
528#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
529pub enum State {
530    #[serde(rename = "Paused")]
531    Paused,
532
533    #[serde(rename = "Running")]
534    Running,
535
536    #[serde(rename = "Completed")]
537    Completed,
538}