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