1 // Take a look at the license at the top of the repository in the LICENSE file. 2 3 use std::ffi::CStr; 4 use std::fmt; 5 use std::mem; 6 7 use glib::translate::{ 8 from_glib, from_glib_full, from_glib_none, FromGlibPtrContainer, IntoGlib, ToGlibPtr, 9 }; 10 11 use crate::TagList; 12 use crate::TagMergeMode; 13 use crate::TocEntryType; 14 use crate::TocLoopType; 15 use crate::TocScope; 16 17 mini_object_wrapper!(Toc, TocRef, ffi::GstToc, || { ffi::gst_toc_get_type() }); 18 19 impl Toc { 20 #[doc(alias = "gst_toc_new")] new(scope: TocScope) -> Self21 pub fn new(scope: TocScope) -> Self { 22 assert_initialized_main_thread!(); 23 unsafe { from_glib_full(ffi::gst_toc_new(scope.into_glib())) } 24 } 25 } 26 27 impl TocRef { 28 #[doc(alias = "get_scope")] 29 #[doc(alias = "gst_toc_get_scope")] scope(&self) -> TocScope30 pub fn scope(&self) -> TocScope { 31 unsafe { from_glib(ffi::gst_toc_get_scope(self.as_ptr())) } 32 } 33 34 #[doc(alias = "gst_toc_find_entry")] find_entry(&self, uid: &str) -> Option<TocEntry>35 pub fn find_entry(&self, uid: &str) -> Option<TocEntry> { 36 unsafe { from_glib_none(ffi::gst_toc_find_entry(self.as_ptr(), uid.to_glib_none().0)) } 37 } 38 39 #[doc(alias = "get_entries")] 40 #[doc(alias = "gst_toc_get_entries")] entries(&self) -> Vec<TocEntry>41 pub fn entries(&self) -> Vec<TocEntry> { 42 unsafe { FromGlibPtrContainer::from_glib_none(ffi::gst_toc_get_entries(self.as_ptr())) } 43 } 44 45 #[doc(alias = "gst_toc_append_entry")] append_entry(&mut self, entry: TocEntry)46 pub fn append_entry(&mut self, entry: TocEntry) { 47 unsafe { 48 ffi::gst_toc_append_entry(self.as_mut_ptr(), entry.into_ptr()); 49 } 50 } 51 52 #[doc(alias = "get_tags")] 53 #[doc(alias = "gst_toc_get_tags")] tags(&self) -> Option<TagList>54 pub fn tags(&self) -> Option<TagList> { 55 unsafe { from_glib_none(ffi::gst_toc_get_tags(self.as_ptr())) } 56 } 57 58 #[doc(alias = "gst_toc_set_tags")] set_tags(&mut self, tag_list: TagList)59 pub fn set_tags(&mut self, tag_list: TagList) { 60 unsafe { 61 ffi::gst_toc_set_tags(self.as_mut_ptr(), tag_list.into_ptr()); 62 } 63 } 64 65 #[doc(alias = "gst_toc_merge_tags")] merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode)66 pub fn merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode) { 67 unsafe { 68 ffi::gst_toc_merge_tags(self.as_mut_ptr(), tag_list.as_mut_ptr(), mode.into_glib()); 69 } 70 } 71 72 #[doc(alias = "gst_toc_dump")] dump(&self)73 pub fn dump(&self) { 74 unsafe { 75 ffi::gst_toc_dump(self.as_mut_ptr()); 76 } 77 } 78 } 79 80 impl fmt::Debug for Toc { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result81 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 82 TocRef::fmt(self, f) 83 } 84 } 85 86 impl fmt::Debug for TocRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 88 f.debug_struct("Toc") 89 .field("scope", &self.scope()) 90 .field("tags", &self.tags()) 91 .field("entries", &self.entries()) 92 .finish() 93 } 94 } 95 96 mini_object_wrapper!(TocEntry, TocEntryRef, ffi::GstTocEntry, || { 97 ffi::gst_toc_entry_get_type() 98 }); 99 100 impl TocEntry { 101 #[doc(alias = "gst_toc_entry_new")] new(type_: TocEntryType, uid: &str) -> Self102 pub fn new(type_: TocEntryType, uid: &str) -> Self { 103 assert_initialized_main_thread!(); 104 unsafe { 105 from_glib_full(ffi::gst_toc_entry_new( 106 type_.into_glib(), 107 uid.to_glib_none().0, 108 )) 109 } 110 } 111 } 112 113 impl TocEntryRef { 114 #[doc(alias = "get_entry_type")] 115 #[doc(alias = "gst_toc_entry_get_entry_type")] entry_type(&self) -> TocEntryType116 pub fn entry_type(&self) -> TocEntryType { 117 unsafe { from_glib(ffi::gst_toc_entry_get_entry_type(self.as_ptr())) } 118 } 119 120 #[doc(alias = "get_uid")] 121 #[doc(alias = "gst_toc_entry_get_uid")] uid(&self) -> &str122 pub fn uid(&self) -> &str { 123 unsafe { 124 CStr::from_ptr(ffi::gst_toc_entry_get_uid(self.as_ptr())) 125 .to_str() 126 .unwrap() 127 } 128 } 129 130 #[doc(alias = "gst_toc_entry_append_sub_entry")] append_sub_entry(&mut self, subentry: TocEntry)131 pub fn append_sub_entry(&mut self, subentry: TocEntry) { 132 unsafe { 133 ffi::gst_toc_entry_append_sub_entry(self.as_mut_ptr(), subentry.into_ptr()); 134 } 135 } 136 137 #[doc(alias = "get_sub_entries")] 138 #[doc(alias = "gst_toc_entry_get_sub_entries")] sub_entries(&self) -> Vec<TocEntry>139 pub fn sub_entries(&self) -> Vec<TocEntry> { 140 unsafe { 141 FromGlibPtrContainer::from_glib_none(ffi::gst_toc_entry_get_sub_entries(self.as_ptr())) 142 } 143 } 144 145 #[doc(alias = "get_parent")] 146 #[doc(alias = "gst_toc_entry_get_parent")] parent(&self) -> Option<TocEntry>147 pub fn parent(&self) -> Option<TocEntry> { 148 unsafe { from_glib_none(ffi::gst_toc_entry_get_parent(self.as_mut_ptr())) } 149 } 150 151 #[doc(alias = "get_start_stop_times")] 152 #[doc(alias = "gst_toc_entry_get_start_stop_times")] start_stop_times(&self) -> Option<(i64, i64)>153 pub fn start_stop_times(&self) -> Option<(i64, i64)> { 154 unsafe { 155 let mut start = mem::MaybeUninit::uninit(); 156 let mut stop = mem::MaybeUninit::uninit(); 157 158 if from_glib(ffi::gst_toc_entry_get_start_stop_times( 159 self.as_ptr(), 160 start.as_mut_ptr(), 161 stop.as_mut_ptr(), 162 )) { 163 Some((start.assume_init(), stop.assume_init())) 164 } else { 165 None 166 } 167 } 168 } 169 170 #[doc(alias = "gst_toc_entry_set_start_stop_times")] set_start_stop_times(&mut self, start: i64, stop: i64)171 pub fn set_start_stop_times(&mut self, start: i64, stop: i64) { 172 unsafe { 173 ffi::gst_toc_entry_set_start_stop_times(self.as_mut_ptr(), start, stop); 174 } 175 } 176 177 #[doc(alias = "get_tags")] 178 #[doc(alias = "gst_toc_entry_get_tags")] tags(&self) -> Option<TagList>179 pub fn tags(&self) -> Option<TagList> { 180 unsafe { from_glib_none(ffi::gst_toc_entry_get_tags(self.as_ptr())) } 181 } 182 183 #[doc(alias = "gst_toc_entry_set_tags")] set_tags(&mut self, tag_list: TagList)184 pub fn set_tags(&mut self, tag_list: TagList) { 185 unsafe { 186 ffi::gst_toc_entry_set_tags(self.as_mut_ptr(), tag_list.into_ptr()); 187 } 188 } 189 190 #[doc(alias = "gst_toc_entry_merge_tags")] merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode)191 pub fn merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode) { 192 unsafe { 193 ffi::gst_toc_entry_merge_tags( 194 self.as_mut_ptr(), 195 tag_list.as_mut_ptr(), 196 mode.into_glib(), 197 ); 198 } 199 } 200 201 #[doc(alias = "gst_toc_entry_is_alternative")] is_alternative(&self) -> bool202 pub fn is_alternative(&self) -> bool { 203 unsafe { from_glib(ffi::gst_toc_entry_is_alternative(self.as_ptr())) } 204 } 205 206 #[doc(alias = "gst_toc_entry_is_sequence")] is_sequence(&self) -> bool207 pub fn is_sequence(&self) -> bool { 208 unsafe { from_glib(ffi::gst_toc_entry_is_sequence(self.as_ptr())) } 209 } 210 211 #[doc(alias = "get_loop")] loop_(&self) -> Option<(TocLoopType, i32)>212 pub fn loop_(&self) -> Option<(TocLoopType, i32)> { 213 unsafe { 214 let mut loop_type = mem::MaybeUninit::uninit(); 215 let mut repeat_count = mem::MaybeUninit::uninit(); 216 if from_glib(ffi::gst_toc_entry_get_loop( 217 self.as_ptr(), 218 loop_type.as_mut_ptr(), 219 repeat_count.as_mut_ptr(), 220 )) { 221 Some(( 222 from_glib(loop_type.assume_init()), 223 repeat_count.assume_init(), 224 )) 225 } else { 226 None 227 } 228 } 229 } 230 231 #[doc(alias = "gst_toc_entry_set_loop")] set_loop(&mut self, loop_type: TocLoopType, repeat_count: i32)232 pub fn set_loop(&mut self, loop_type: TocLoopType, repeat_count: i32) { 233 unsafe { 234 ffi::gst_toc_entry_set_loop(self.as_mut_ptr(), loop_type.into_glib(), repeat_count); 235 } 236 } 237 } 238 239 impl fmt::Debug for TocEntry { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 241 TocEntryRef::fmt(self, f) 242 } 243 } 244 245 impl fmt::Debug for TocEntryRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result246 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 247 f.debug_struct("TocEntry") 248 .field("entry_type", &self.entry_type()) 249 .field("uid", &self.uid()) 250 .field("start_stop", &self.start_stop_times()) 251 .field("tags", &self.tags()) 252 .field("is_alternative", &self.is_alternative()) 253 .field("is_sequence", &self.is_sequence()) 254 .field("loop", &self.loop_()) 255 .field("sub_entries", &self.sub_entries()) 256 .finish() 257 } 258 } 259 260 #[cfg(test)] 261 mod tests { 262 use super::*; 263 264 #[test] test_simple()265 fn test_simple() { 266 crate::init().unwrap(); 267 268 // Top level toc entry 269 let mut toc_entry = TocEntry::new(TocEntryType::Chapter, "chapter"); 270 toc_entry.get_mut().unwrap().set_start_stop_times(1, 10); 271 272 // Toc sub entry 273 let toc_sub_entry = TocEntry::new(TocEntryType::Angle, "angle"); 274 let parent = toc_sub_entry.parent(); 275 assert!(parent.is_none()); 276 277 // Append sub entry 278 toc_entry.get_mut().unwrap().append_sub_entry(toc_sub_entry); 279 280 // Toc 281 let mut toc = Toc::new(TocScope::Global); 282 assert_eq!(toc.scope(), TocScope::Global); 283 284 // Append toc entry 285 toc.get_mut().unwrap().append_entry(toc_entry); 286 assert_eq!(toc.scope(), TocScope::Global); 287 288 // Check toc entries 289 let toc_entries = toc.entries(); 290 assert_eq!(toc_entries.len(), 1); 291 292 let toc_parent_entry = &toc_entries[0]; 293 assert_eq!(toc_parent_entry.entry_type(), TocEntryType::Chapter); 294 assert_eq!(toc_parent_entry.uid(), "chapter"); 295 let start_stop_times = toc_parent_entry.start_stop_times(); 296 assert!(start_stop_times.is_some()); 297 assert_eq!(start_stop_times.unwrap(), (1, 10)); 298 299 // Check sub entry 300 let toc_sub_entries = toc_parent_entry.sub_entries(); 301 assert_eq!(toc_sub_entries.len(), 1); 302 let toc_sub_entry = &toc_sub_entries[0]; 303 assert_eq!(toc_sub_entry.entry_type(), TocEntryType::Angle); 304 let parent = toc_sub_entry.parent(); 305 assert!(parent.is_some()); 306 assert_eq!(parent.unwrap().entry_type(), TocEntryType::Chapter); 307 } 308 } 309