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