1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{ffi::CStr, fmt, mem, ptr};
4
5use glib::translate::{
6 from_glib, from_glib_full, from_glib_none, FromGlibPtrContainer, IntoGlib, IntoGlibPtr,
7 ToGlibPtr,
8};
9
10use crate::{TagList, TagMergeMode, TocEntryType, TocLoopType, TocScope};
11
12mini_object_wrapper!(Toc, TocRef, ffi::GstToc, || { ffi::gst_toc_get_type() });
13
14impl 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
22impl 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
88impl fmt::Debug for Toc {
89 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 TocRef::fmt(self, f)
91 }
92}
93
94impl 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
104mini_object_wrapper!(TocEntry, TocEntryRef, ffi::GstTocEntry, || {
105 ffi::gst_toc_entry_get_type()
106});
107
108impl 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
121impl 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
256impl fmt::Debug for TocEntry {
257 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
258 TocEntryRef::fmt(self, f)
259 }
260}
261
262impl 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)]
278mod 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