oxihuman_export/
aaf_export.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum AafEssenceKind {
10 Video,
11 Audio,
12 Data,
13}
14
15#[derive(Debug, Clone)]
17pub struct AafComponent {
18 pub name: String,
19 pub kind: AafEssenceKind,
20 pub length_frames: u32,
21 pub source_ref: String,
22}
23
24#[derive(Debug, Clone)]
26pub struct AafTrack {
27 pub track_id: u32,
28 pub label: String,
29 pub components: Vec<AafComponent>,
30}
31
32#[derive(Debug, Clone)]
34pub struct AafExport {
35 pub name: String,
36 pub edit_rate: (u32, u32), pub tracks: Vec<AafTrack>,
38}
39
40pub fn new_aaf_export(name: &str, edit_rate_num: u32, edit_rate_den: u32) -> AafExport {
42 AafExport {
43 name: name.to_string(),
44 edit_rate: (edit_rate_num, edit_rate_den),
45 tracks: Vec::new(),
46 }
47}
48
49pub fn aaf_add_track(export: &mut AafExport, track_id: u32, label: &str) {
51 export.tracks.push(AafTrack {
52 track_id,
53 label: label.to_string(),
54 components: Vec::new(),
55 });
56}
57
58pub fn aaf_add_component(
60 export: &mut AafExport,
61 name: &str,
62 kind: AafEssenceKind,
63 length: u32,
64 source_ref: &str,
65) {
66 if let Some(track) = export.tracks.last_mut() {
67 track.components.push(AafComponent {
68 name: name.to_string(),
69 kind,
70 length_frames: length,
71 source_ref: source_ref.to_string(),
72 });
73 }
74}
75
76pub fn aaf_track_count(export: &AafExport) -> usize {
78 export.tracks.len()
79}
80
81pub fn aaf_component_count(export: &AafExport) -> usize {
83 export.tracks.iter().map(|t| t.components.len()).sum()
84}
85
86pub fn aaf_duration_frames(export: &AafExport) -> u32 {
88 export
89 .tracks
90 .first()
91 .map(|t| t.components.iter().map(|c| c.length_frames).sum())
92 .unwrap_or(0)
93}
94
95pub fn validate_aaf(export: &AafExport) -> bool {
97 !export.name.is_empty() && export.edit_rate.1 > 0
98}
99
100pub fn aaf_to_xml_stub(export: &AafExport) -> String {
102 format!(
103 "<AAFFile><Composition name=\"{}\" editRate=\"{}/{}\"/></AAFFile>",
104 export.name, export.edit_rate.0, export.edit_rate.1
105 )
106}
107
108pub fn aaf_size_estimate(export: &AafExport) -> usize {
110 aaf_to_xml_stub(export).len() + aaf_component_count(export) * 64
111}
112
113pub fn aaf_find_track(export: &AafExport, track_id: u32) -> Option<&AafTrack> {
115 export.tracks.iter().find(|t| t.track_id == track_id)
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 fn sample() -> AafExport {
123 let mut exp = new_aaf_export("MyComp", 24, 1);
124 aaf_add_track(&mut exp, 1, "V1");
125 aaf_add_component(&mut exp, "clip1", AafEssenceKind::Video, 48, "mob:001");
126 aaf_add_component(&mut exp, "clip2", AafEssenceKind::Video, 24, "mob:002");
127 aaf_add_track(&mut exp, 2, "A1");
128 aaf_add_component(&mut exp, "audio1", AafEssenceKind::Audio, 72, "mob:003");
129 exp
130 }
131
132 #[test]
133 fn test_track_count() {
134 assert_eq!(aaf_track_count(&sample()), 2);
135 }
136
137 #[test]
138 fn test_component_count() {
139 assert_eq!(aaf_component_count(&sample()), 3);
140 }
141
142 #[test]
143 fn test_duration_frames() {
144 assert_eq!(aaf_duration_frames(&sample()), 72);
145 }
146
147 #[test]
148 fn test_validate_valid() {
149 assert!(validate_aaf(&sample()));
150 }
151
152 #[test]
153 fn test_validate_bad_rate() {
154 let exp = new_aaf_export("X", 24, 0);
155 assert!(!validate_aaf(&exp));
156 }
157
158 #[test]
159 fn test_to_xml() {
160 let s = aaf_to_xml_stub(&sample());
161 assert!(s.contains("MyComp"));
162 }
163
164 #[test]
165 fn test_find_track() {
166 let exp = sample();
167 assert!(aaf_find_track(&exp, 1).is_some());
168 assert!(aaf_find_track(&exp, 99).is_none());
169 }
170
171 #[test]
172 fn test_size_estimate() {
173 assert!(aaf_size_estimate(&sample()) > 0);
174 }
175
176 #[test]
177 fn test_empty_duration() {
178 let exp = new_aaf_export("empty", 25, 1);
179 assert_eq!(aaf_duration_frames(&exp), 0);
180 }
181}