gstreamer/
segment.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, marker::PhantomData, mem};
4
5use glib::{prelude::*, translate::*};
6
7use crate::{
8    ffi,
9    format::{
10        CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic,
11        FormattedValueNoneBuilder, NoneSignedBuilder, UnsignedIntoSigned,
12    },
13    Format, GenericFormattedValue, SeekFlags, SeekType,
14};
15
16pub type Segment = FormattedSegment<GenericFormattedValue>;
17
18glib::wrapper! {
19    #[doc(alias = "GstSegment")]
20    pub struct FormattedSegment<T: FormattedValueIntrinsic>(BoxedInline<ffi::GstSegment>);
21
22    match fn {
23        copy => |ptr| ffi::gst_segment_copy(ptr),
24        free => |ptr| ffi::gst_segment_free(ptr),
25        init => |_ptr| (),
26        copy_into => |dest, src| { *dest = *src; },
27        clear => |_ptr| (),
28    }
29}
30
31impl Segment {
32    #[inline]
33    pub fn reset_with_format(&mut self, format: Format) {
34        unsafe {
35            ffi::gst_segment_init(self.to_glib_none_mut().0, format.into_glib());
36        }
37    }
38
39    #[inline]
40    pub fn set_format(&mut self, format: Format) {
41        self.inner.format = format.into_glib();
42    }
43
44    #[inline]
45    pub fn downcast<T: FormattedValueIntrinsic>(self) -> Result<FormattedSegment<T>, Self> {
46        if T::default_format() == Format::Undefined || T::default_format() == self.format() {
47            Ok(FormattedSegment {
48                inner: self.inner,
49                phantom: PhantomData,
50            })
51        } else {
52            Err(self)
53        }
54    }
55
56    #[inline]
57    pub fn downcast_ref<T: FormattedValueIntrinsic>(&self) -> Option<&FormattedSegment<T>> {
58        if T::default_format() == Format::Undefined || T::default_format() == self.format() {
59            Some(unsafe {
60                &*(self as *const FormattedSegment<GenericFormattedValue>
61                    as *const FormattedSegment<T>)
62            })
63        } else {
64            None
65        }
66    }
67
68    #[inline]
69    pub fn downcast_mut<T: FormattedValueIntrinsic>(&mut self) -> Option<&mut FormattedSegment<T>> {
70        if T::default_format() == Format::Undefined || T::default_format() == self.format() {
71            Some(unsafe {
72                &mut *(self as *mut FormattedSegment<GenericFormattedValue>
73                    as *mut FormattedSegment<T>)
74            })
75        } else {
76            None
77        }
78    }
79}
80
81impl<T: FormattedValueIntrinsic> FormattedSegment<T> {
82    #[inline]
83    pub fn new() -> Self {
84        assert_initialized_main_thread!();
85        let segment = unsafe {
86            let mut segment = mem::MaybeUninit::uninit();
87            ffi::gst_segment_init(segment.as_mut_ptr(), T::default_format().into_glib());
88            segment.assume_init()
89        };
90        FormattedSegment {
91            inner: segment,
92            phantom: PhantomData,
93        }
94    }
95
96    #[inline]
97    pub fn upcast(self) -> Segment {
98        FormattedSegment {
99            inner: self.inner,
100            phantom: PhantomData,
101        }
102    }
103
104    #[inline]
105    pub fn upcast_ref(&self) -> &Segment {
106        unsafe {
107            &*(self as *const FormattedSegment<T> as *const FormattedSegment<GenericFormattedValue>)
108        }
109    }
110
111    #[inline]
112    pub fn reset(&mut self) {
113        unsafe {
114            ffi::gst_segment_init(&mut self.inner, T::default_format().into_glib());
115        }
116    }
117
118    #[doc(alias = "gst_segment_clip")]
119    pub fn clip(
120        &self,
121        start: impl CompatibleFormattedValue<T>,
122        stop: impl CompatibleFormattedValue<T>,
123    ) -> Option<(T::FullRange, T::FullRange)> {
124        let start = start.try_into_checked_explicit(self.format()).unwrap();
125        let stop = stop.try_into_checked_explicit(self.format()).unwrap();
126
127        unsafe {
128            let mut clip_start = mem::MaybeUninit::uninit();
129            let mut clip_stop = mem::MaybeUninit::uninit();
130            let ret = from_glib(ffi::gst_segment_clip(
131                &self.inner,
132                start.format().into_glib(),
133                start.into_raw_value() as u64,
134                stop.into_raw_value() as u64,
135                clip_start.as_mut_ptr(),
136                clip_stop.as_mut_ptr(),
137            ));
138            if ret {
139                Some((
140                    T::FullRange::from_raw(self.format(), clip_start.assume_init() as i64),
141                    T::FullRange::from_raw(self.format(), clip_stop.assume_init() as i64),
142                ))
143            } else {
144                None
145            }
146        }
147    }
148
149    #[allow(clippy::too_many_arguments)]
150    #[doc(alias = "gst_segment_do_seek")]
151    pub fn do_seek(
152        &mut self,
153        rate: f64,
154        flags: SeekFlags,
155        start_type: SeekType,
156        start: impl CompatibleFormattedValue<T>,
157        stop_type: SeekType,
158        stop: impl CompatibleFormattedValue<T>,
159    ) -> Option<bool> {
160        let start = start.try_into_checked_explicit(self.format()).unwrap();
161        let stop = stop.try_into_checked_explicit(self.format()).unwrap();
162
163        unsafe {
164            let mut update = mem::MaybeUninit::uninit();
165            let ret = from_glib(ffi::gst_segment_do_seek(
166                &mut self.inner,
167                rate,
168                self.format().into_glib(),
169                flags.into_glib(),
170                start_type.into_glib(),
171                start.into_raw_value() as u64,
172                stop_type.into_glib(),
173                stop.into_raw_value() as u64,
174                update.as_mut_ptr(),
175            ));
176            if ret {
177                Some(from_glib(update.assume_init()))
178            } else {
179                None
180            }
181        }
182    }
183
184    #[doc(alias = "gst_segment_offset_running_time")]
185    #[inline]
186    pub fn offset_running_time(&mut self, offset: i64) -> Result<(), glib::BoolError> {
187        unsafe {
188            glib::result_from_gboolean!(
189                ffi::gst_segment_offset_running_time(
190                    &mut self.inner,
191                    self.format().into_glib(),
192                    offset,
193                ),
194                "Offset is not in the segment"
195            )
196        }
197    }
198
199    #[doc(alias = "gst_segment_set_running_time")]
200    #[inline]
201    pub fn set_running_time(
202        &mut self,
203        running_time: impl CompatibleFormattedValue<T>,
204    ) -> Result<(), glib::BoolError> {
205        let running_time = running_time
206            .try_into_checked_explicit(self.format())
207            .unwrap();
208
209        unsafe {
210            glib::result_from_gboolean!(
211                ffi::gst_segment_set_running_time(
212                    &mut self.inner,
213                    self.format().into_glib(),
214                    running_time.into_raw_value() as u64,
215                ),
216                "Running time is not in the segment"
217            )
218        }
219    }
220
221    #[doc(alias = "get_flags")]
222    #[inline]
223    pub fn flags(&self) -> crate::SegmentFlags {
224        unsafe { from_glib(self.inner.flags) }
225    }
226
227    #[inline]
228    pub fn set_flags(&mut self, flags: crate::SegmentFlags) {
229        self.inner.flags = flags.into_glib();
230    }
231
232    #[doc(alias = "get_rate")]
233    #[inline]
234    pub fn rate(&self) -> f64 {
235        self.inner.rate
236    }
237
238    #[allow(clippy::float_cmp)]
239    #[inline]
240    pub fn set_rate(&mut self, rate: f64) {
241        assert_ne!(rate, 0.0);
242        self.inner.rate = rate;
243    }
244
245    #[doc(alias = "get_applied_rate")]
246    #[inline]
247    pub fn applied_rate(&self) -> f64 {
248        self.inner.applied_rate
249    }
250
251    #[allow(clippy::float_cmp)]
252    #[inline]
253    pub fn set_applied_rate(&mut self, applied_rate: f64) {
254        assert_ne!(applied_rate, 0.0);
255        self.inner.applied_rate = applied_rate;
256    }
257
258    #[doc(alias = "get_format")]
259    #[inline]
260    pub fn format(&self) -> Format {
261        unsafe { from_glib(self.inner.format) }
262    }
263
264    #[doc(alias = "get_base")]
265    #[inline]
266    pub fn base(&self) -> T::FullRange {
267        unsafe { T::FullRange::from_raw(self.format(), self.inner.base as i64) }
268    }
269
270    #[inline]
271    pub fn set_base(&mut self, base: impl CompatibleFormattedValue<T>) {
272        let base = base.try_into_checked_explicit(self.format()).unwrap();
273        self.inner.base = unsafe { base.into_raw_value() } as u64;
274    }
275
276    #[doc(alias = "get_offset")]
277    #[inline]
278    pub fn offset(&self) -> T::FullRange {
279        unsafe { T::FullRange::from_raw(self.format(), self.inner.offset as i64) }
280    }
281
282    #[inline]
283    pub fn set_offset(&mut self, offset: impl CompatibleFormattedValue<T>) {
284        let offset = offset.try_into_checked_explicit(self.format()).unwrap();
285        self.inner.offset = unsafe { offset.into_raw_value() } as u64;
286    }
287
288    #[doc(alias = "get_start")]
289    #[inline]
290    pub fn start(&self) -> T::FullRange {
291        unsafe { T::FullRange::from_raw(self.format(), self.inner.start as i64) }
292    }
293
294    #[inline]
295    pub fn set_start(&mut self, start: impl CompatibleFormattedValue<T>) {
296        let start = start.try_into_checked_explicit(self.format()).unwrap();
297        self.inner.start = unsafe { start.into_raw_value() } as u64;
298    }
299
300    #[doc(alias = "get_stop")]
301    #[inline]
302    pub fn stop(&self) -> T::FullRange {
303        unsafe { T::FullRange::from_raw(self.format(), self.inner.stop as i64) }
304    }
305
306    #[inline]
307    pub fn set_stop(&mut self, stop: impl CompatibleFormattedValue<T>) {
308        let stop = stop.try_into_checked_explicit(self.format()).unwrap();
309        self.inner.stop = unsafe { stop.into_raw_value() } as u64;
310    }
311
312    #[doc(alias = "get_time")]
313    #[inline]
314    pub fn time(&self) -> T::FullRange {
315        unsafe { T::FullRange::from_raw(self.format(), self.inner.time as i64) }
316    }
317
318    #[inline]
319    pub fn set_time(&mut self, time: impl CompatibleFormattedValue<T>) {
320        let time = time.try_into_checked_explicit(self.format()).unwrap();
321        self.inner.time = unsafe { time.into_raw_value() } as u64;
322    }
323
324    #[doc(alias = "get_position")]
325    #[inline]
326    pub fn position(&self) -> T::FullRange {
327        unsafe { T::FullRange::from_raw(self.format(), self.inner.position as i64) }
328    }
329
330    #[inline]
331    pub fn set_position(&mut self, position: impl CompatibleFormattedValue<T>) {
332        let position = position.try_into_checked_explicit(self.format()).unwrap();
333        self.inner.position = unsafe { position.into_raw_value() } as u64;
334    }
335
336    #[doc(alias = "get_duration")]
337    #[inline]
338    pub fn duration(&self) -> T::FullRange {
339        unsafe { T::FullRange::from_raw(self.format(), self.inner.duration as i64) }
340    }
341
342    #[inline]
343    pub fn set_duration(&mut self, duration: impl CompatibleFormattedValue<T>) {
344        let duration = duration.try_into_checked_explicit(self.format()).unwrap();
345        self.inner.duration = unsafe { duration.into_raw_value() } as u64;
346    }
347}
348
349impl<T: FormattedValueIntrinsic> PartialEq for FormattedSegment<T> {
350    #[inline]
351    #[doc(alias = "gst_segment_is_equal")]
352    fn eq(&self, other: &Self) -> bool {
353        unsafe { from_glib(ffi::gst_segment_is_equal(&self.inner, &other.inner)) }
354    }
355}
356
357impl<T> FormattedSegment<T>
358where
359    T: FormattedValueIntrinsic,
360    T::FullRange: FormattedValueNoneBuilder,
361{
362    #[doc(alias = "gst_segment_position_from_running_time")]
363    pub fn position_from_running_time(
364        &self,
365        running_time: impl CompatibleFormattedValue<T>,
366    ) -> T::FullRange {
367        let running_time = running_time
368            .try_into_checked_explicit(self.format())
369            .unwrap();
370        if running_time.is_none() {
371            return T::FullRange::none_for_format(self.format());
372        }
373
374        unsafe {
375            T::FullRange::from_raw(
376                self.format(),
377                ffi::gst_segment_position_from_running_time(
378                    &self.inner,
379                    self.format().into_glib(),
380                    running_time.into_raw_value() as u64,
381                ) as i64,
382            )
383        }
384    }
385
386    #[doc(alias = "gst_segment_position_from_stream_time")]
387    pub fn position_from_stream_time(
388        &self,
389        stream_time: impl CompatibleFormattedValue<T>,
390    ) -> T::FullRange {
391        let stream_time = stream_time
392            .try_into_checked_explicit(self.format())
393            .unwrap();
394        if stream_time.is_none() {
395            return T::FullRange::none_for_format(self.format());
396        }
397
398        unsafe {
399            T::FullRange::from_raw(
400                self.format(),
401                ffi::gst_segment_position_from_stream_time(
402                    &self.inner,
403                    self.format().into_glib(),
404                    stream_time.into_raw_value() as u64,
405                ) as i64,
406            )
407        }
408    }
409
410    #[doc(alias = "gst_segment_to_running_time")]
411    pub fn to_running_time(&self, position: impl CompatibleFormattedValue<T>) -> T::FullRange {
412        let position = position.try_into_checked_explicit(self.format()).unwrap();
413        if position.is_none() {
414            return T::FullRange::none_for_format(self.format());
415        }
416
417        unsafe {
418            T::FullRange::from_raw(
419                self.format(),
420                ffi::gst_segment_to_running_time(
421                    &self.inner,
422                    self.format().into_glib(),
423                    position.into_raw_value() as u64,
424                ) as i64,
425            )
426        }
427    }
428
429    #[doc(alias = "gst_segment_to_stream_time")]
430    pub fn to_stream_time(&self, position: impl CompatibleFormattedValue<T>) -> T::FullRange {
431        let position = position.try_into_checked_explicit(self.format()).unwrap();
432        if position.is_none() {
433            return T::FullRange::none_for_format(self.format());
434        }
435
436        unsafe {
437            T::FullRange::from_raw(
438                self.format(),
439                ffi::gst_segment_to_stream_time(
440                    &self.inner,
441                    self.format().into_glib(),
442                    position.into_raw_value() as u64,
443                ) as i64,
444            )
445        }
446    }
447}
448
449impl<T> FormattedSegment<T>
450where
451    T: FormattedValueIntrinsic,
452    T::FullRange: UnsignedIntoSigned,
453    T::FullRange: NoneSignedBuilder<Signed = <T::FullRange as UnsignedIntoSigned>::Signed>,
454{
455    #[doc(alias = "gst_segment_position_from_running_time_full")]
456    pub fn position_from_running_time_full(
457        &self,
458        running_time: impl CompatibleFormattedValue<T>,
459    ) -> <T::FullRange as UnsignedIntoSigned>::Signed {
460        let running_time = running_time
461            .try_into_checked_explicit(self.format())
462            .unwrap();
463        if running_time.is_none() {
464            return T::FullRange::none_signed_for_format(self.format());
465        }
466
467        unsafe {
468            let mut position = mem::MaybeUninit::uninit();
469            let sign = ffi::gst_segment_position_from_running_time_full(
470                &self.inner,
471                self.format().into_glib(),
472                running_time.into_raw_value() as u64,
473                position.as_mut_ptr(),
474            );
475
476            T::FullRange::from_raw(self.format(), position.assume_init() as i64).into_signed(sign)
477        }
478    }
479
480    #[doc(alias = "gst_segment_position_from_stream_time_full")]
481    pub fn position_from_stream_time_full(
482        &self,
483        stream_time: impl CompatibleFormattedValue<T>,
484    ) -> <T::FullRange as UnsignedIntoSigned>::Signed {
485        let stream_time = stream_time
486            .try_into_checked_explicit(self.format())
487            .unwrap();
488        if stream_time.is_none() {
489            return T::FullRange::none_signed_for_format(self.format());
490        }
491
492        unsafe {
493            let mut position = mem::MaybeUninit::uninit();
494            let sign = ffi::gst_segment_position_from_stream_time_full(
495                &self.inner,
496                self.format().into_glib(),
497                stream_time.into_raw_value() as u64,
498                position.as_mut_ptr(),
499            );
500
501            T::FullRange::from_raw(self.format(), position.assume_init() as i64).into_signed(sign)
502        }
503    }
504
505    #[doc(alias = "gst_segment_to_running_time_full")]
506    pub fn to_running_time_full(
507        &self,
508        position: impl CompatibleFormattedValue<T>,
509    ) -> <T::FullRange as UnsignedIntoSigned>::Signed {
510        let position = position.try_into_checked_explicit(self.format()).unwrap();
511        if position.is_none() {
512            return T::FullRange::none_signed_for_format(self.format());
513        }
514
515        unsafe {
516            let mut running_time = mem::MaybeUninit::uninit();
517            let sign = ffi::gst_segment_to_running_time_full(
518                &self.inner,
519                self.format().into_glib(),
520                position.into_raw_value() as u64,
521                running_time.as_mut_ptr(),
522            );
523
524            T::FullRange::from_raw(self.format(), running_time.assume_init() as i64)
525                .into_signed(sign)
526        }
527    }
528
529    #[doc(alias = "gst_segment_to_stream_time_full")]
530    pub fn to_stream_time_full(
531        &self,
532        position: impl CompatibleFormattedValue<T>,
533    ) -> <T::FullRange as UnsignedIntoSigned>::Signed {
534        let position = position.try_into_checked_explicit(self.format()).unwrap();
535        if position.is_none() {
536            return T::FullRange::none_signed_for_format(self.format());
537        }
538
539        unsafe {
540            let mut stream_time = mem::MaybeUninit::uninit();
541            let sign = ffi::gst_segment_to_stream_time_full(
542                &self.inner,
543                self.format().into_glib(),
544                position.into_raw_value() as u64,
545                stream_time.as_mut_ptr(),
546            );
547
548            T::FullRange::from_raw(self.format(), stream_time.assume_init() as i64)
549                .into_signed(sign)
550        }
551    }
552}
553
554impl<T: FormattedValueIntrinsic> Eq for FormattedSegment<T> {}
555
556unsafe impl<T: FormattedValueIntrinsic> Send for FormattedSegment<T> {}
557unsafe impl<T: FormattedValueIntrinsic> Sync for FormattedSegment<T> {}
558
559impl<T: FormattedValueIntrinsic> AsRef<Segment> for FormattedSegment<T> {
560    #[inline]
561    fn as_ref(&self) -> &Segment {
562        unsafe {
563            &*(self as *const FormattedSegment<T> as *const FormattedSegment<GenericFormattedValue>)
564        }
565    }
566}
567
568impl<T: FormattedValueIntrinsic> fmt::Debug for FormattedSegment<T> {
569    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
570        use crate::utils::Displayable;
571
572        let segment = self.as_ref();
573        match segment.format() {
574            Format::Undefined => f
575                .debug_struct("Segment")
576                .field("format", &Format::Undefined)
577                .finish(),
578            Format::Time => {
579                let segment = segment.downcast_ref::<crate::ClockTime>().unwrap();
580                f.debug_struct("Segment")
581                    .field("format", &Format::Time)
582                    .field("start", &segment.start().display())
583                    .field("offset", &segment.offset().display())
584                    .field("stop", &segment.stop().display())
585                    .field("rate", &segment.rate())
586                    .field("applied_rate", &segment.applied_rate())
587                    .field("flags", &segment.flags())
588                    .field("time", &segment.time().display())
589                    .field("base", &segment.base().display())
590                    .field("position", &segment.position().display())
591                    .field("duration", &segment.duration().display())
592                    .finish()
593            }
594            _ => f
595                .debug_struct("Segment")
596                .field("format", &segment.format())
597                .field("start", &segment.start())
598                .field("offset", &segment.offset())
599                .field("stop", &segment.stop())
600                .field("rate", &segment.rate())
601                .field("applied_rate", &segment.applied_rate())
602                .field("flags", &segment.flags())
603                .field("time", &segment.time())
604                .field("base", &segment.base())
605                .field("position", &segment.position())
606                .field("duration", &segment.duration())
607                .finish(),
608        }
609    }
610}
611
612impl<T: FormattedValueIntrinsic> Default for FormattedSegment<T> {
613    #[inline]
614    fn default() -> Self {
615        Self::new()
616    }
617}
618
619impl<T: FormattedValueIntrinsic> glib::types::StaticType for FormattedSegment<T> {
620    #[inline]
621    fn static_type() -> glib::types::Type {
622        unsafe { glib::translate::from_glib(ffi::gst_segment_get_type()) }
623    }
624}
625
626impl glib::value::ValueType for Segment {
627    type Type = Self;
628}
629
630#[doc(hidden)]
631unsafe impl<'a> glib::value::FromValue<'a> for Segment {
632    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
633
634    #[inline]
635    unsafe fn from_value(value: &'a glib::Value) -> Self {
636        skip_assert_initialized!();
637        from_glib_none(
638            glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *mut ffi::GstSegment
639        )
640    }
641}
642
643#[doc(hidden)]
644unsafe impl<'a> glib::value::FromValue<'a> for &'a Segment {
645    type Checker = glib::value::GenericValueTypeOrNoneChecker<Self>;
646
647    #[inline]
648    unsafe fn from_value(value: &'a glib::Value) -> Self {
649        skip_assert_initialized!();
650        Segment::from_glib_ptr_borrow(
651            glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) as *const ffi::GstSegment
652        )
653    }
654}
655
656#[doc(hidden)]
657impl<T: FormattedValueIntrinsic> glib::value::ToValue for FormattedSegment<T> {
658    #[inline]
659    fn to_value(&self) -> glib::Value {
660        let mut value = glib::Value::for_value_type::<Segment>();
661        unsafe {
662            glib::gobject_ffi::g_value_set_boxed(
663                value.to_glib_none_mut().0,
664                self.to_glib_none().0 as *mut _,
665            )
666        }
667        value
668    }
669
670    #[inline]
671    fn value_type(&self) -> glib::Type {
672        Self::static_type()
673    }
674}
675
676#[doc(hidden)]
677impl<T: FormattedValueIntrinsic> glib::value::ToValueOptional for FormattedSegment<T> {
678    #[inline]
679    fn to_value_optional(s: Option<&Self>) -> glib::Value {
680        skip_assert_initialized!();
681        let mut value = glib::Value::for_value_type::<Segment>();
682        unsafe {
683            glib::gobject_ffi::g_value_set_boxed(
684                value.to_glib_none_mut().0,
685                s.to_glib_none().0 as *mut _,
686            )
687        }
688        value
689    }
690}
691
692impl<T: FormattedValueIntrinsic> From<FormattedSegment<T>> for glib::Value {
693    #[inline]
694    fn from(v: FormattedSegment<T>) -> glib::Value {
695        skip_assert_initialized!();
696        glib::value::ToValue::to_value(&v)
697    }
698}