1 // Copyright (C) 2016-2017 Sebastian Dröge <sebastian@centricular.com> 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 use std::ffi::CStr; 10 use std::fmt; 11 use std::mem; 12 13 use gst_sys; 14 15 use glib; 16 use glib::translate::{ 17 from_glib, from_glib_full, from_glib_none, FromGlibPtrContainer, ToGlib, ToGlibPtr, 18 }; 19 20 use miniobject::*; 21 use TagList; 22 use TagMergeMode; 23 use TocEntryType; 24 use TocLoopType; 25 use TocScope; 26 27 gst_define_mini_object_wrapper!(Toc, TocRef, gst_sys::GstToc, [Debug,], || { 28 gst_sys::gst_toc_get_type() 29 }); 30 31 impl Toc { new(scope: TocScope) -> Self32 pub fn new(scope: TocScope) -> Self { 33 assert_initialized_main_thread!(); 34 unsafe { from_glib_full(gst_sys::gst_toc_new(scope.to_glib())) } 35 } 36 } 37 38 impl TocRef { get_scope(&self) -> TocScope39 pub fn get_scope(&self) -> TocScope { 40 unsafe { from_glib(gst_sys::gst_toc_get_scope(self.as_ptr())) } 41 } 42 find_entry(&self, uid: &str) -> Option<TocEntry>43 pub fn find_entry(&self, uid: &str) -> Option<TocEntry> { 44 unsafe { 45 from_glib_none(gst_sys::gst_toc_find_entry( 46 self.as_ptr(), 47 uid.to_glib_none().0, 48 )) 49 } 50 } 51 get_entries(&self) -> Vec<TocEntry>52 pub fn get_entries(&self) -> Vec<TocEntry> { 53 unsafe { FromGlibPtrContainer::from_glib_none(gst_sys::gst_toc_get_entries(self.as_ptr())) } 54 } 55 append_entry(&mut self, entry: TocEntry)56 pub fn append_entry(&mut self, entry: TocEntry) { 57 unsafe { 58 gst_sys::gst_toc_append_entry(self.as_mut_ptr(), entry.into_ptr()); 59 } 60 } 61 get_tags(&self) -> Option<TagList>62 pub fn get_tags(&self) -> Option<TagList> { 63 unsafe { from_glib_none(gst_sys::gst_toc_get_tags(self.as_ptr())) } 64 } 65 set_tags(&mut self, tag_list: TagList)66 pub fn set_tags(&mut self, tag_list: TagList) { 67 unsafe { 68 gst_sys::gst_toc_set_tags(self.as_mut_ptr(), tag_list.into_ptr()); 69 } 70 } 71 merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode)72 pub fn merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode) { 73 unsafe { 74 gst_sys::gst_toc_merge_tags(self.as_mut_ptr(), tag_list.as_mut_ptr(), mode.to_glib()); 75 } 76 } 77 dump(&self)78 pub fn dump(&self) { 79 unsafe { 80 gst_sys::gst_toc_dump(self.as_mut_ptr()); 81 } 82 } 83 } 84 85 impl fmt::Debug for TocRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result86 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 87 f.debug_struct("Toc") 88 .field("scope", &self.get_scope()) 89 .field("tags", &self.get_tags()) 90 .field("entries", &self.get_entries()) 91 .finish() 92 } 93 } 94 95 gst_define_mini_object_wrapper!( 96 TocEntry, 97 TocEntryRef, 98 gst_sys::GstTocEntry, 99 [Debug,], 100 || gst_sys::gst_toc_entry_get_type() 101 ); 102 103 impl TocEntry { new(type_: TocEntryType, uid: &str) -> Self104 pub fn new(type_: TocEntryType, uid: &str) -> Self { 105 assert_initialized_main_thread!(); 106 unsafe { 107 from_glib_full(gst_sys::gst_toc_entry_new( 108 type_.to_glib(), 109 uid.to_glib_none().0, 110 )) 111 } 112 } 113 } 114 115 impl TocEntryRef { get_entry_type(&self) -> TocEntryType116 pub fn get_entry_type(&self) -> TocEntryType { 117 unsafe { from_glib(gst_sys::gst_toc_entry_get_entry_type(self.as_ptr())) } 118 } 119 get_uid(&self) -> &str120 pub fn get_uid(&self) -> &str { 121 unsafe { 122 CStr::from_ptr(gst_sys::gst_toc_entry_get_uid(self.as_ptr())) 123 .to_str() 124 .unwrap() 125 } 126 } 127 append_sub_entry(&mut self, subentry: TocEntry)128 pub fn append_sub_entry(&mut self, subentry: TocEntry) { 129 unsafe { 130 gst_sys::gst_toc_entry_append_sub_entry(self.as_mut_ptr(), subentry.into_ptr()); 131 } 132 } 133 get_sub_entries(&self) -> Vec<TocEntry>134 pub fn get_sub_entries(&self) -> Vec<TocEntry> { 135 unsafe { 136 FromGlibPtrContainer::from_glib_none(gst_sys::gst_toc_entry_get_sub_entries( 137 self.as_ptr(), 138 )) 139 } 140 } 141 get_parent(&self) -> Option<TocEntry>142 pub fn get_parent(&self) -> Option<TocEntry> { 143 unsafe { from_glib_none(gst_sys::gst_toc_entry_get_parent(self.as_mut_ptr())) } 144 } 145 get_start_stop_times(&self) -> Option<(i64, i64)>146 pub fn get_start_stop_times(&self) -> Option<(i64, i64)> { 147 unsafe { 148 let mut start = mem::MaybeUninit::uninit(); 149 let mut stop = mem::MaybeUninit::uninit(); 150 151 if from_glib(gst_sys::gst_toc_entry_get_start_stop_times( 152 self.as_ptr(), 153 start.as_mut_ptr(), 154 stop.as_mut_ptr(), 155 )) { 156 Some((start.assume_init(), stop.assume_init())) 157 } else { 158 None 159 } 160 } 161 } 162 set_start_stop_times(&mut self, start: i64, stop: i64)163 pub fn set_start_stop_times(&mut self, start: i64, stop: i64) { 164 unsafe { 165 gst_sys::gst_toc_entry_set_start_stop_times(self.as_mut_ptr(), start, stop); 166 } 167 } 168 get_tags(&self) -> Option<TagList>169 pub fn get_tags(&self) -> Option<TagList> { 170 unsafe { from_glib_none(gst_sys::gst_toc_entry_get_tags(self.as_ptr())) } 171 } 172 set_tags(&mut self, tag_list: TagList)173 pub fn set_tags(&mut self, tag_list: TagList) { 174 unsafe { 175 gst_sys::gst_toc_entry_set_tags(self.as_mut_ptr(), tag_list.into_ptr()); 176 } 177 } 178 merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode)179 pub fn merge_tags(&mut self, tag_list: &TagList, mode: TagMergeMode) { 180 unsafe { 181 gst_sys::gst_toc_entry_merge_tags( 182 self.as_mut_ptr(), 183 tag_list.as_mut_ptr(), 184 mode.to_glib(), 185 ); 186 } 187 } 188 is_alternative(&self) -> bool189 pub fn is_alternative(&self) -> bool { 190 unsafe { from_glib(gst_sys::gst_toc_entry_is_alternative(self.as_ptr())) } 191 } 192 is_sequence(&self) -> bool193 pub fn is_sequence(&self) -> bool { 194 unsafe { from_glib(gst_sys::gst_toc_entry_is_sequence(self.as_ptr())) } 195 } 196 get_loop(&self) -> Option<(TocLoopType, i32)>197 pub fn get_loop(&self) -> Option<(TocLoopType, i32)> { 198 unsafe { 199 let mut loop_type = mem::MaybeUninit::uninit(); 200 let mut repeat_count = mem::MaybeUninit::uninit(); 201 if from_glib(gst_sys::gst_toc_entry_get_loop( 202 self.as_ptr(), 203 loop_type.as_mut_ptr(), 204 repeat_count.as_mut_ptr(), 205 )) { 206 Some(( 207 from_glib(loop_type.assume_init()), 208 repeat_count.assume_init(), 209 )) 210 } else { 211 None 212 } 213 } 214 } 215 set_loop(&mut self, loop_type: TocLoopType, repeat_count: i32)216 pub fn set_loop(&mut self, loop_type: TocLoopType, repeat_count: i32) { 217 unsafe { 218 gst_sys::gst_toc_entry_set_loop(self.as_mut_ptr(), loop_type.to_glib(), repeat_count); 219 } 220 } 221 } 222 223 impl fmt::Debug for TocEntryRef { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result224 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 225 f.debug_struct("TocEntry") 226 .field("entry_type", &self.get_entry_type()) 227 .field("uid", &self.get_uid()) 228 .field("start_stop", &self.get_start_stop_times()) 229 .field("tags", &self.get_tags()) 230 .field("is_alternative", &self.is_alternative()) 231 .field("is_sequence", &self.is_sequence()) 232 .field("loop", &self.get_loop()) 233 .field("sub_entries", &self.get_sub_entries()) 234 .finish() 235 } 236 } 237 238 #[cfg(test)] 239 mod tests { 240 use super::*; 241 242 #[test] test_simple()243 fn test_simple() { 244 ::init().unwrap(); 245 246 // Top level toc entry 247 let mut toc_entry = TocEntry::new(TocEntryType::Chapter, "chapter"); 248 toc_entry.get_mut().unwrap().set_start_stop_times(1, 10); 249 250 // Toc sub entry 251 let toc_sub_entry = TocEntry::new(TocEntryType::Angle, "angle"); 252 let parent = toc_sub_entry.get_parent(); 253 assert!(parent.is_none()); 254 255 // Append sub entry 256 toc_entry.get_mut().unwrap().append_sub_entry(toc_sub_entry); 257 258 // Toc 259 let mut toc = Toc::new(TocScope::Global); 260 assert_eq!(toc.get_scope(), TocScope::Global); 261 262 // Append toc entry 263 toc.get_mut().unwrap().append_entry(toc_entry); 264 assert_eq!(toc.get_scope(), TocScope::Global); 265 266 // Check toc entries 267 let toc_entries = toc.get_entries(); 268 assert_eq!(toc_entries.len(), 1); 269 270 let toc_parent_entry = &toc_entries[0]; 271 assert_eq!(toc_parent_entry.get_entry_type(), TocEntryType::Chapter); 272 assert_eq!(toc_parent_entry.get_uid(), "chapter"); 273 let start_stop_times = toc_parent_entry.get_start_stop_times(); 274 assert!(start_stop_times.is_some()); 275 assert_eq!(start_stop_times.unwrap(), (1, 10)); 276 277 // Check sub entry 278 let toc_sub_entries = toc_parent_entry.get_sub_entries(); 279 assert_eq!(toc_sub_entries.len(), 1); 280 let toc_sub_entry = &toc_sub_entries[0]; 281 assert_eq!(toc_sub_entry.get_entry_type(), TocEntryType::Angle); 282 let parent = toc_sub_entry.get_parent(); 283 assert!(parent.is_some()); 284 assert_eq!(parent.unwrap().get_entry_type(), TocEntryType::Chapter); 285 } 286 } 287