gstreamer_pbutils/
encoding_profile.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{prelude::*, translate::*};
4
5#[cfg(feature = "v1_20")]
6use crate::ElementProperties;
7use crate::{
8    ffi, EncodingAudioProfile, EncodingContainerProfile, EncodingProfile, EncodingVideoProfile,
9};
10
11pub trait EncodingProfileExtManual: IsA<EncodingProfile> + 'static {
12    #[cfg(feature = "v1_20")]
13    #[cfg_attr(docsrs, doc(cfg(feature = "v1_20")))]
14    #[doc(alias = "gst_encoding_profile_get_element_properties")]
15    #[doc(alias = "get_element_properties")]
16    fn element_properties(&self) -> Option<ElementProperties> {
17        unsafe {
18            from_glib_full::<_, Option<_>>(ffi::gst_encoding_profile_get_element_properties(
19                self.as_ref().to_glib_none().0,
20            ))
21            .map(ElementProperties)
22        }
23    }
24}
25
26impl<O: IsA<EncodingProfile>> EncodingProfileExtManual for O {}
27
28trait EncodingProfileBuilderCommon {
29    fn set_allow_dynamic_output(&self, allow_dynamic_output: bool);
30
31    fn set_description(&self, description: Option<&str>);
32
33    fn set_enabled(&self, enabled: bool);
34
35    fn set_format(&self, format: &gst::Caps);
36
37    fn set_name(&self, name: Option<&str>);
38
39    fn set_presence(&self, presence: u32);
40
41    fn set_preset(&self, preset: Option<&str>);
42
43    fn set_preset_name(&self, preset_name: Option<&str>);
44
45    #[cfg(feature = "v1_18")]
46    fn set_single_segment(&self, single_segment: bool);
47
48    #[cfg(feature = "v1_20")]
49    fn set_element_properties(&self, element_properties: ElementProperties);
50}
51
52impl<O: IsA<EncodingProfile>> EncodingProfileBuilderCommon for O {
53    // checker-ignore-item
54    fn set_allow_dynamic_output(&self, allow_dynamic_output: bool) {
55        unsafe {
56            ffi::gst_encoding_profile_set_allow_dynamic_output(
57                self.as_ref().to_glib_none().0,
58                allow_dynamic_output.into_glib(),
59            );
60        }
61    }
62
63    // checker-ignore-item
64    fn set_description(&self, description: Option<&str>) {
65        let description = description.to_glib_none();
66        unsafe {
67            ffi::gst_encoding_profile_set_description(
68                self.as_ref().to_glib_none().0,
69                description.0,
70            );
71        }
72    }
73
74    // checker-ignore-item
75    fn set_enabled(&self, enabled: bool) {
76        unsafe {
77            ffi::gst_encoding_profile_set_enabled(
78                self.as_ref().to_glib_none().0,
79                enabled.into_glib(),
80            );
81        }
82    }
83
84    // checker-ignore-item
85    fn set_format(&self, format: &gst::Caps) {
86        unsafe {
87            ffi::gst_encoding_profile_set_format(
88                self.as_ref().to_glib_none().0,
89                format.to_glib_none().0,
90            );
91        }
92    }
93
94    // checker-ignore-item
95    fn set_name(&self, name: Option<&str>) {
96        let name = name.to_glib_none();
97        unsafe {
98            ffi::gst_encoding_profile_set_name(self.as_ref().to_glib_none().0, name.0);
99        }
100    }
101
102    // checker-ignore-item
103    fn set_presence(&self, presence: u32) {
104        unsafe {
105            ffi::gst_encoding_profile_set_presence(self.as_ref().to_glib_none().0, presence);
106        }
107    }
108
109    // checker-ignore-item
110    fn set_preset(&self, preset: Option<&str>) {
111        let preset = preset.to_glib_none();
112        unsafe {
113            ffi::gst_encoding_profile_set_preset(self.as_ref().to_glib_none().0, preset.0);
114        }
115    }
116
117    // checker-ignore-item
118    fn set_preset_name(&self, preset_name: Option<&str>) {
119        let preset_name = preset_name.to_glib_none();
120        unsafe {
121            ffi::gst_encoding_profile_set_preset_name(
122                self.as_ref().to_glib_none().0,
123                preset_name.0,
124            );
125        }
126    }
127
128    // checker-ignore-item
129    #[cfg(feature = "v1_18")]
130    fn set_single_segment(&self, single_segment: bool) {
131        unsafe {
132            ffi::gst_encoding_profile_set_single_segment(
133                self.as_ref().to_glib_none().0,
134                single_segment.into_glib(),
135            );
136        }
137    }
138
139    // checker-ignore-item
140    #[cfg(feature = "v1_20")]
141    fn set_element_properties(&self, element_properties: ElementProperties) {
142        unsafe {
143            ffi::gst_encoding_profile_set_element_properties(
144                self.as_ref().to_glib_none().0,
145                element_properties.into_inner().into_glib_ptr(),
146            );
147        }
148    }
149}
150
151pub trait EncodingProfileHasRestrictionGetter {
152    #[doc(alias = "get_restriction")]
153    #[doc(alias = "gst_encoding_profile_get_restriction")]
154    fn restriction(&self) -> Option<gst::Caps>;
155}
156
157macro_rules! declare_encoding_profile_has_restriction(
158    ($name:ident) => {
159        impl EncodingProfileHasRestrictionGetter for $name {
160            // checker-ignore-item
161            fn restriction(&self) -> Option<gst::Caps> {
162                let profile: &EncodingProfile = glib::object::Cast::upcast_ref(self);
163
164                unsafe {
165                   from_glib_full(ffi::gst_encoding_profile_get_restriction(
166                       profile.to_glib_none().0,
167                   ))
168               }
169            }
170        }
171    }
172);
173
174impl EncodingAudioProfile {
175    // checker-ignore-item
176    fn new(
177        format: &gst::Caps,
178        preset: Option<&str>,
179        restriction: Option<&gst::Caps>,
180        presence: u32,
181    ) -> EncodingAudioProfile {
182        skip_assert_initialized!();
183        let preset = preset.to_glib_none();
184        let restriction = restriction.to_glib_none();
185        unsafe {
186            from_glib_full(ffi::gst_encoding_audio_profile_new(
187                format.to_glib_none().0,
188                preset.0,
189                restriction.0,
190                presence,
191            ))
192        }
193    }
194
195    #[doc(alias = "gst_encoding_audio_profile_new")]
196    pub fn builder(format: &gst::Caps) -> EncodingAudioProfileBuilder<'_> {
197        assert_initialized_main_thread!();
198        EncodingAudioProfileBuilder::new(format)
199    }
200}
201
202declare_encoding_profile_has_restriction!(EncodingAudioProfile);
203
204impl EncodingVideoProfile {
205    // checker-ignore-item
206    fn new(
207        format: &gst::Caps,
208        preset: Option<&str>,
209        restriction: Option<&gst::Caps>,
210        presence: u32,
211    ) -> EncodingVideoProfile {
212        skip_assert_initialized!();
213        let preset = preset.to_glib_none();
214        let restriction = restriction.to_glib_none();
215        unsafe {
216            from_glib_full(ffi::gst_encoding_video_profile_new(
217                format.to_glib_none().0,
218                preset.0,
219                restriction.0,
220                presence,
221            ))
222        }
223    }
224
225    #[doc(alias = "gst_encoding_video_profile_new")]
226    pub fn builder(format: &gst::Caps) -> EncodingVideoProfileBuilder<'_> {
227        assert_initialized_main_thread!();
228        EncodingVideoProfileBuilder::new(format)
229    }
230
231    // checker-ignore-item
232    fn set_pass(&self, pass: u32) {
233        unsafe {
234            ffi::gst_encoding_video_profile_set_pass(self.to_glib_none().0, pass);
235        }
236    }
237
238    // checker-ignore-item
239    fn set_variableframerate(&self, variableframerate: bool) {
240        unsafe {
241            ffi::gst_encoding_video_profile_set_variableframerate(
242                self.to_glib_none().0,
243                variableframerate.into_glib(),
244            );
245        }
246    }
247}
248
249declare_encoding_profile_has_restriction!(EncodingVideoProfile);
250
251impl EncodingContainerProfile {
252    // checker-ignore-item
253    fn new(
254        name: Option<&str>,
255        description: Option<&str>,
256        format: &gst::Caps,
257        preset: Option<&str>,
258    ) -> EncodingContainerProfile {
259        skip_assert_initialized!();
260        let name = name.to_glib_none();
261        let description = description.to_glib_none();
262        let preset = preset.to_glib_none();
263        unsafe {
264            from_glib_full(ffi::gst_encoding_container_profile_new(
265                name.0,
266                description.0,
267                format.to_glib_none().0,
268                preset.0,
269            ))
270        }
271    }
272
273    #[doc(alias = "gst_encoding_container_profile_new")]
274    pub fn builder(format: &gst::Caps) -> EncodingContainerProfileBuilder<'_> {
275        assert_initialized_main_thread!();
276        EncodingContainerProfileBuilder::new(format)
277    }
278
279    // checker-ignore-item
280    fn add_profile(&self, profile: impl IsA<EncodingProfile>) {
281        unsafe {
282            let res = ffi::gst_encoding_container_profile_add_profile(
283                self.to_glib_none().0,
284                profile.upcast().into_glib_ptr(),
285            );
286            // Can't possibly fail unless we pass random pointers
287            debug_assert_ne!(res, glib::ffi::GFALSE);
288        }
289    }
290}
291
292#[derive(Debug)]
293struct EncodingProfileBuilderCommonData<'a> {
294    format: &'a gst::Caps,
295    name: Option<&'a str>,
296    description: Option<&'a str>,
297    preset: Option<&'a str>,
298    preset_name: Option<&'a str>,
299    presence: u32,
300    allow_dynamic_output: bool,
301    enabled: bool,
302    #[cfg(feature = "v1_18")]
303    single_segment: bool,
304    #[cfg(feature = "v1_20")]
305    element_properties: Option<ElementProperties>,
306}
307
308impl<'a> EncodingProfileBuilderCommonData<'a> {
309    fn new(format: &'a gst::Caps) -> EncodingProfileBuilderCommonData<'a> {
310        skip_assert_initialized!();
311        EncodingProfileBuilderCommonData {
312            name: None,
313            description: None,
314            format,
315            preset: None,
316            preset_name: None,
317            presence: 0,
318            allow_dynamic_output: true,
319            enabled: true,
320            #[cfg(feature = "v1_18")]
321            single_segment: false,
322            #[cfg(feature = "v1_20")]
323            element_properties: None,
324        }
325    }
326}
327
328pub trait EncodingProfileBuilder<'a>: Sized {
329    #[doc(alias = "gst_encoding_profile_set_name")]
330    #[must_use]
331    fn name(self, name: &'a str) -> Self;
332    #[doc(alias = "gst_encoding_profile_set_description")]
333    #[must_use]
334    fn description(self, description: &'a str) -> Self;
335    #[doc(alias = "gst_encoding_profile_set_preset")]
336    #[must_use]
337    fn preset(self, preset: &'a str) -> Self;
338    #[doc(alias = "gst_encoding_profile_set_preset_name")]
339    #[must_use]
340    fn preset_name(self, preset_name: &'a str) -> Self;
341    #[doc(alias = "gst_encoding_profile_set_presence")]
342    #[must_use]
343    fn presence(self, presence: u32) -> Self;
344    #[doc(alias = "gst_encoding_profile_set_presence")]
345    #[must_use]
346    fn presence_if(self, presence: u32, predicate: bool) -> Self;
347    #[doc(alias = "gst_encoding_profile_set_presence")]
348    #[must_use]
349    fn presence_if_some(self, presence: Option<u32>) -> Self;
350    #[doc(alias = "gst_encoding_profile_set_allow_dynamic_output")]
351    #[must_use]
352    fn allow_dynamic_output(self, allow: bool) -> Self;
353    #[doc(alias = "gst_encoding_profile_set_allow_dynamic_output")]
354    #[must_use]
355    fn allow_dynamic_output_if_some(self, allow_dynamic_output: Option<bool>) -> Self;
356    #[doc(alias = "gst_encoding_profile_set_enabled")]
357    #[must_use]
358    fn enabled(self, enabled: bool) -> Self;
359    #[doc(alias = "gst_encoding_profile_set_enabled")]
360    #[must_use]
361    fn enabled_if_some(self, enabled: Option<bool>) -> Self;
362    #[cfg(feature = "v1_18")]
363    #[doc(alias = "gst_encoding_profile_set_single_segment")]
364    #[must_use]
365    fn single_segment(self, single_segment: bool) -> Self;
366    #[cfg(feature = "v1_18")]
367    #[doc(alias = "gst_encoding_profile_set_single_segment")]
368    #[must_use]
369    fn single_segment_if_some(self, single_segment: Option<bool>) -> Self;
370    #[cfg(feature = "v1_20")]
371    #[doc(alias = "gst_encoding_profile_set_element_properties")]
372    #[must_use]
373    fn element_properties(self, element_properties: ElementProperties) -> Self;
374    #[cfg(feature = "v1_20")]
375    #[doc(alias = "gst_encoding_profile_set_element_properties")]
376    #[must_use]
377    fn element_properties_if(self, element_properties: ElementProperties, predecate: bool) -> Self;
378    #[cfg(feature = "v1_20")]
379    #[doc(alias = "gst_encoding_profile_set_element_properties")]
380    #[must_use]
381    fn element_properties_if_some(self, element_properties: Option<ElementProperties>) -> Self;
382}
383
384macro_rules! declare_encoding_profile_builder_common(
385    ($name:ident) => {
386        impl<'a> EncodingProfileBuilder<'a> for $name<'a> {
387            fn name(mut self, name: &'a str) -> $name<'a> {
388                self.base.name = Some(name);
389                self
390            }
391
392            fn description(mut self, description: &'a str) -> $name<'a> {
393                self.base.description = Some(description);
394                self
395            }
396
397            fn preset(mut self, preset: &'a str) -> $name<'a> {
398                self.base.preset = Some(preset);
399                self
400            }
401
402            fn preset_name(mut self, preset_name: &'a str) -> $name<'a> {
403                self.base.preset_name = Some(preset_name);
404                self
405            }
406
407            fn presence(mut self, presence: u32) -> $name<'a> {
408                self.base.presence = presence;
409                self
410            }
411
412            fn presence_if(self, presence: u32, predicate: bool) -> $name<'a> {
413                if predicate {
414                    self.presence(presence)
415                } else {
416                    self
417                }
418            }
419
420            fn presence_if_some(self, presence: Option<u32>) -> $name<'a> {
421                if let Some(presence) = presence {
422                    self.presence(presence)
423                } else {
424                    self
425                }
426            }
427
428            fn allow_dynamic_output(mut self, allow: bool) -> $name<'a> {
429                self.base.allow_dynamic_output = allow;
430                self
431            }
432
433            fn allow_dynamic_output_if_some(self, allow_dynamic_output: Option<bool>) -> $name<'a> {
434                if let Some(allow_dynamic_output) = allow_dynamic_output {
435                    self.allow_dynamic_output(allow_dynamic_output)
436                } else {
437                    self
438                }
439            }
440
441            fn enabled(mut self, enabled: bool) -> $name<'a> {
442                self.base.enabled = enabled;
443                self
444            }
445
446            fn enabled_if_some(self, enabled: Option<bool>) -> $name<'a> {
447                if let Some(enabled) = enabled {
448                    self.enabled(enabled)
449                } else {
450                    self
451                }
452            }
453
454            #[cfg(feature = "v1_18")]
455            fn single_segment(mut self, single_segment: bool) -> $name<'a> {
456                self.base.single_segment = single_segment;
457                self
458            }
459
460            #[cfg(feature = "v1_18")]
461            fn single_segment_if_some(self, single_segment: Option<bool>) -> $name<'a> {
462                if let Some(single_segment) = single_segment {
463                    self.single_segment(single_segment)
464                } else {
465                    self
466                }
467            }
468
469            #[cfg(feature = "v1_20")]
470            fn element_properties(mut self, element_properties: ElementProperties) -> $name<'a> {
471                self.base.element_properties = Some(element_properties);
472                self
473            }
474
475            #[cfg(feature = "v1_20")]
476            fn element_properties_if(self, element_properties: ElementProperties, predicate: bool) -> $name<'a> {
477                if predicate {
478                    self.element_properties(element_properties)
479                } else {
480                    self
481                }
482            }
483
484            #[cfg(feature = "v1_20")]
485            fn element_properties_if_some(self, element_properties: Option<ElementProperties>) -> $name<'a> {
486                if let Some(element_properties) = element_properties {
487                    self.element_properties(element_properties)
488                } else {
489                    self
490                }
491            }
492        }
493    }
494);
495
496fn set_common_fields<T: EncodingProfileBuilderCommon>(
497    profile: &T,
498    base_data: EncodingProfileBuilderCommonData,
499) {
500    skip_assert_initialized!();
501    profile.set_format(base_data.format);
502    profile.set_name(base_data.name);
503    profile.set_description(base_data.description);
504    profile.set_preset(base_data.preset);
505    profile.set_preset_name(base_data.preset_name);
506    profile.set_allow_dynamic_output(base_data.allow_dynamic_output);
507    profile.set_enabled(base_data.enabled);
508    profile.set_presence(base_data.presence);
509    #[cfg(feature = "v1_18")]
510    {
511        profile.set_single_segment(base_data.single_segment);
512    }
513    #[cfg(feature = "v1_20")]
514    {
515        let mut base_data = base_data;
516        if let Some(element_properties) = base_data.element_properties.take() {
517            profile.set_element_properties(element_properties);
518        }
519    }
520}
521
522#[derive(Debug)]
523#[must_use = "The builder must be built to be used"]
524pub struct EncodingAudioProfileBuilder<'a> {
525    base: EncodingProfileBuilderCommonData<'a>,
526    restriction: Option<&'a gst::Caps>,
527}
528
529declare_encoding_profile_builder_common!(EncodingAudioProfileBuilder);
530
531impl<'a> EncodingAudioProfileBuilder<'a> {
532    fn new(format: &'a gst::Caps) -> Self {
533        skip_assert_initialized!();
534        EncodingAudioProfileBuilder {
535            base: EncodingProfileBuilderCommonData::new(format),
536            restriction: None,
537        }
538    }
539
540    #[doc(alias = "gst_encoding_profile_set_restriction")]
541    pub fn restriction(mut self, restriction: &'a gst::Caps) -> Self {
542        self.restriction = Some(restriction);
543        self
544    }
545
546    #[must_use = "Building the profile without using it has no effect"]
547    pub fn build(self) -> EncodingAudioProfile {
548        let profile = EncodingAudioProfile::new(
549            self.base.format,
550            self.base.preset,
551            self.restriction,
552            self.base.presence,
553        );
554
555        set_common_fields(&profile, self.base);
556
557        profile
558    }
559}
560
561#[derive(Debug)]
562#[must_use = "The builder must be built to be used"]
563pub struct EncodingVideoProfileBuilder<'a> {
564    base: EncodingProfileBuilderCommonData<'a>,
565    restriction: Option<&'a gst::Caps>,
566    pass: u32,
567    variable_framerate: bool,
568}
569
570declare_encoding_profile_builder_common!(EncodingVideoProfileBuilder);
571
572impl<'a> EncodingVideoProfileBuilder<'a> {
573    fn new(format: &'a gst::Caps) -> Self {
574        skip_assert_initialized!();
575        EncodingVideoProfileBuilder {
576            base: EncodingProfileBuilderCommonData::new(format),
577            restriction: None,
578            pass: 0,
579            variable_framerate: false,
580        }
581    }
582
583    #[doc(alias = "gst_encoding_video_profile_set_pass")]
584    pub fn pass(mut self, pass: u32) -> Self {
585        self.pass = pass;
586        self
587    }
588
589    #[doc(alias = "gst_encoding_video_profile_set_variableframerate")]
590    pub fn variable_framerate(mut self, variable_framerate: bool) -> Self {
591        self.variable_framerate = variable_framerate;
592        self
593    }
594
595    #[doc(alias = "gst_encoding_profile_set_restriction")]
596    pub fn restriction(mut self, restriction: &'a gst::Caps) -> Self {
597        self.restriction = Some(restriction);
598        self
599    }
600
601    #[must_use = "Building the profile without using it has no effect"]
602    pub fn build(self) -> EncodingVideoProfile {
603        let video_profile = EncodingVideoProfile::new(
604            self.base.format,
605            self.base.preset,
606            self.restriction,
607            self.base.presence,
608        );
609
610        video_profile.set_pass(self.pass);
611        video_profile.set_variableframerate(self.variable_framerate);
612
613        set_common_fields(&video_profile, self.base);
614
615        video_profile
616    }
617}
618
619#[derive(Debug)]
620#[must_use = "The builder must be built to be used"]
621pub struct EncodingContainerProfileBuilder<'a> {
622    base: EncodingProfileBuilderCommonData<'a>,
623    profiles: Vec<EncodingProfile>,
624}
625
626declare_encoding_profile_builder_common!(EncodingContainerProfileBuilder);
627
628impl<'a> EncodingContainerProfileBuilder<'a> {
629    fn new(format: &'a gst::Caps) -> Self {
630        skip_assert_initialized!();
631        EncodingContainerProfileBuilder {
632            base: EncodingProfileBuilderCommonData::new(format),
633            profiles: Vec::new(),
634        }
635    }
636
637    #[must_use = "Building the profile without using it has no effect"]
638    pub fn build(self) -> EncodingContainerProfile {
639        let container_profile = EncodingContainerProfile::new(
640            self.base.name,
641            self.base.description,
642            self.base.format,
643            self.base.preset,
644        );
645
646        for profile in self.profiles {
647            container_profile.add_profile(profile);
648        }
649
650        set_common_fields(&container_profile, self.base);
651
652        container_profile
653    }
654
655    #[doc(alias = "gst_encoding_container_profile_add_profile")]
656    pub fn add_profile(mut self, profile: impl IsA<EncodingProfile>) -> Self {
657        self.profiles.push(profile.upcast());
658        self
659    }
660}
661
662#[cfg(test)]
663mod tests {
664    use super::*;
665    use crate::{
666        auto::{EncodingContainerProfile, EncodingVideoProfile},
667        prelude::*,
668    };
669
670    const AUDIO_PROFILE_NAME: &str = "audio-profile";
671    const AUDIO_PROFILE_DESCRIPTION: &str = "audio-profile-description";
672    const PRESET: &str = "preset";
673    const PRESET_NAME: &str = "preset-name";
674    const PRESENCE: u32 = 5;
675    const ALLOW_DYNAMIC_OUTPUT: bool = false;
676    const ENABLED: bool = false;
677
678    const VIDEO_PROFILE_NAME: &str = "video-profile";
679    const VIDEO_PROFILE_DESCRIPTION: &str = "video-profile-description";
680
681    const CONTAINER_PROFILE_NAME: &str = "container-profile";
682    const CONTAINER_PROFILE_DESCRIPTION: &str = "container-profile-description";
683
684    // Video profile exclusive attributes
685    const PASS: u32 = 8;
686    const VARIABLE_FRAMERATE: bool = true;
687
688    #[test]
689    fn test_encoding_audio_profile_builder() {
690        gst::init().unwrap();
691
692        let caps = gst::Caps::builder("audio/x-raw").build();
693
694        let restriction = gst_audio::AudioCapsBuilder::new()
695            .format(gst_audio::AudioFormat::S32le)
696            .build();
697
698        let audio_profile = EncodingAudioProfile::builder(&caps)
699            .name(AUDIO_PROFILE_NAME)
700            .description(AUDIO_PROFILE_DESCRIPTION)
701            .preset(PRESET)
702            .preset_name(PRESET_NAME)
703            .restriction(&restriction)
704            .presence(PRESENCE)
705            .allow_dynamic_output(ALLOW_DYNAMIC_OUTPUT)
706            .enabled(ENABLED)
707            .build();
708
709        assert_eq!(audio_profile.name().unwrap(), AUDIO_PROFILE_NAME);
710        assert_eq!(
711            audio_profile.description().unwrap(),
712            AUDIO_PROFILE_DESCRIPTION
713        );
714        assert_eq!(audio_profile.format(), caps);
715        assert_eq!(audio_profile.preset().unwrap(), PRESET);
716        assert_eq!(audio_profile.preset_name().unwrap(), PRESET_NAME);
717        assert_eq!(audio_profile.restriction().unwrap(), restriction);
718        assert_eq!(audio_profile.presence(), PRESENCE);
719        assert_eq!(audio_profile.allows_dynamic_output(), ALLOW_DYNAMIC_OUTPUT);
720        assert_eq!(audio_profile.is_enabled(), ENABLED);
721    }
722
723    #[test]
724    fn test_encoding_video_profile_builder() {
725        gst::init().unwrap();
726
727        let caps = gst::Caps::builder("video/x-raw").build();
728
729        let restriction = gst_video::VideoCapsBuilder::new()
730            .format(gst_video::VideoFormat::Rgba)
731            .build();
732
733        let video_profile = EncodingVideoProfile::builder(&caps)
734            .name(VIDEO_PROFILE_NAME)
735            .description(VIDEO_PROFILE_DESCRIPTION)
736            .preset(PRESET)
737            .preset_name(PRESET_NAME)
738            .restriction(&restriction)
739            .presence(PRESENCE)
740            .allow_dynamic_output(ALLOW_DYNAMIC_OUTPUT)
741            .enabled(ENABLED)
742            .pass(PASS)
743            .variable_framerate(VARIABLE_FRAMERATE)
744            .build();
745
746        assert_eq!(video_profile.name().unwrap(), VIDEO_PROFILE_NAME);
747        assert_eq!(
748            video_profile.description().unwrap(),
749            VIDEO_PROFILE_DESCRIPTION
750        );
751        assert_eq!(video_profile.format(), caps);
752        assert_eq!(video_profile.preset().unwrap(), PRESET);
753        assert_eq!(video_profile.preset_name().unwrap(), PRESET_NAME);
754        assert_eq!(video_profile.restriction().unwrap(), restriction);
755        assert_eq!(video_profile.presence(), PRESENCE);
756        assert_eq!(video_profile.allows_dynamic_output(), ALLOW_DYNAMIC_OUTPUT);
757        assert_eq!(video_profile.is_enabled(), ENABLED);
758
759        let video_profile: EncodingVideoProfile =
760            glib::object::Cast::downcast(video_profile).ok().unwrap();
761        assert_eq!(video_profile.is_variableframerate(), VARIABLE_FRAMERATE);
762        assert_eq!(video_profile.pass(), PASS);
763    }
764
765    #[test]
766    fn test_encoding_container_profile_builder() {
767        gst::init().unwrap();
768
769        let container_caps = gst::Caps::builder("container/x-caps").build();
770        let video_caps = gst::Caps::builder("video/x-raw").build();
771        let audio_caps = gst::Caps::builder("audio/x-raw").build();
772
773        let video_profile = EncodingVideoProfile::builder(&video_caps)
774            .name(VIDEO_PROFILE_NAME)
775            .description(VIDEO_PROFILE_DESCRIPTION)
776            .build();
777        let audio_profile = EncodingAudioProfile::builder(&audio_caps)
778            .name(AUDIO_PROFILE_NAME)
779            .description(AUDIO_PROFILE_DESCRIPTION)
780            .build();
781
782        let profile = EncodingContainerProfile::builder(&container_caps)
783            .name(CONTAINER_PROFILE_NAME)
784            .description(CONTAINER_PROFILE_DESCRIPTION)
785            .preset(PRESET)
786            .preset_name(PRESET_NAME)
787            .presence(PRESENCE)
788            .allow_dynamic_output(ALLOW_DYNAMIC_OUTPUT)
789            .enabled(ENABLED)
790            .add_profile(audio_profile.clone())
791            .add_profile(video_profile.clone())
792            .build();
793
794        assert_eq!(profile.name().unwrap(), CONTAINER_PROFILE_NAME);
795        assert_eq!(
796            profile.description().unwrap(),
797            CONTAINER_PROFILE_DESCRIPTION
798        );
799        assert_eq!(profile.format(), container_caps);
800        assert_eq!(profile.preset().unwrap(), PRESET);
801        assert_eq!(profile.preset_name().unwrap(), PRESET_NAME);
802        assert_eq!(profile.presence(), PRESENCE);
803        assert_eq!(profile.allows_dynamic_output(), ALLOW_DYNAMIC_OUTPUT);
804        assert_eq!(profile.is_enabled(), ENABLED);
805
806        let container_profile: EncodingContainerProfile =
807            glib::object::Cast::downcast(profile).ok().unwrap();
808
809        assert!(container_profile.contains_profile(&video_profile));
810        assert!(container_profile.contains_profile(&audio_profile));
811    }
812}