Skip to main content

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