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