libobs_wrapper\encoders/
property_helper.rs

1use std::{collections::HashMap, str::FromStr, sync::Arc};
2
3use duplicate::duplicate_item;
4
5use crate::{
6    context::ObsContext,
7    data::{
8        output::{ObsOutputRef, ObsOutputTrait},
9        properties::{
10            ObsProperty, ObsPropertyObject, ObsPropertyObjectPrivate, _ObsPropertiesDropGuard,
11            property_ptr_to_struct,
12        },
13        ObsData,
14    },
15    run_with_obs,
16    runtime::ObsRuntime,
17    unsafe_send::{Sendable, SmartPointerSendable},
18    utils::{ObjectInfo, ObsError, ObsString},
19};
20
21use super::{
22    audio::ObsAudioEncoder, video::ObsVideoEncoder, ObsAudioEncoderType, ObsVideoEncoderType,
23};
24
25#[duplicate_item(
26    StructName EncoderType;
27    [ObsAudioEncoderBuilder] [ObsAudioEncoderType];
28    [ObsVideoEncoderBuilder] [ObsVideoEncoderType]
29)]
30#[derive(Debug)]
31pub struct StructName {
32    encoder_id: EncoderType,
33    runtime: ObsRuntime,
34    //TODO: keeping this for now, maybe it'll be useful later
35    _context: ObsContext,
36    settings: Option<ObsData>,
37    hotkey_data: Option<ObsData>,
38}
39
40#[duplicate_item(
41    StructName EncoderType;
42    [ObsAudioEncoderBuilder] [ObsAudioEncoderType];
43    [ObsVideoEncoderBuilder] [ObsVideoEncoderType]
44)]
45impl StructName {
46    pub fn new(context: ObsContext, encoder_id: &str) -> Self {
47        Self {
48            encoder_id: EncoderType::from_str(encoder_id).unwrap(),
49            runtime: context.runtime().clone(),
50            _context: context,
51            settings: None,
52            hotkey_data: None,
53        }
54    }
55
56    pub fn get_encoder_id(&self) -> &EncoderType {
57        &self.encoder_id
58    }
59
60    pub fn set_settings(&mut self, settings: ObsData) -> &mut Self {
61        self.settings = Some(settings);
62        self
63    }
64
65    pub fn set_hotkey_data(&mut self, hotkey_data: ObsData) -> &mut Self {
66        self.hotkey_data = Some(hotkey_data);
67        self
68    }
69
70    pub fn get_settings(&self) -> Option<&ObsData> {
71        self.settings.as_ref()
72    }
73
74    pub fn get_hotkey_data(&self) -> Option<&ObsData> {
75        self.hotkey_data.as_ref()
76    }
77
78    pub fn get_settings_mut(&mut self) -> Option<&mut ObsData> {
79        self.settings.as_mut()
80    }
81
82    pub fn get_hotkey_data_mut(&mut self) -> Option<&mut ObsData> {
83        self.hotkey_data.as_mut()
84    }
85}
86
87impl ObsAudioEncoderBuilder {
88    pub fn apply_to_context(
89        self,
90        output: &mut dyn ObsOutputTrait,
91        name: &str,
92        settings: Option<ObsData>,
93        hotkey_data: Option<ObsData>,
94        mixer_idx: usize,
95    ) -> Result<Arc<ObsAudioEncoder>, ObsError> {
96        let e_id: ObsString = self.encoder_id.into();
97        let info = ObjectInfo::new(e_id, ObsString::new(name), settings, hotkey_data);
98
99        output.create_and_set_audio_encoder(info, mixer_idx)
100    }
101}
102
103impl ObsVideoEncoderBuilder {
104    pub fn set_to_output(
105        self,
106        output: &mut ObsOutputRef,
107        name: &str,
108    ) -> Result<Arc<ObsVideoEncoder>, ObsError> {
109        let e_id: ObsString = self.encoder_id.into();
110        let info = ObjectInfo::new(e_id, ObsString::new(name), self.settings, self.hotkey_data);
111
112        output.create_and_set_video_encoder(info)
113    }
114}
115
116#[duplicate_item(
117    StructName;
118    [ObsAudioEncoderBuilder];
119    [ObsVideoEncoderBuilder]
120)]
121impl ObsPropertyObject for StructName {
122    fn get_properties(&self) -> Result<HashMap<String, ObsProperty>, ObsError> {
123        let properties_raw = self.get_properties_raw()?;
124        property_ptr_to_struct(properties_raw, self.runtime.clone())
125    }
126}
127
128#[duplicate_item(
129    StructName;
130    [ObsAudioEncoderBuilder];
131    [ObsVideoEncoderBuilder]
132)]
133impl ObsPropertyObjectPrivate for StructName {
134    fn get_properties_raw(
135        &self,
136    ) -> Result<SmartPointerSendable<*mut libobs::obs_properties_t>, ObsError> {
137        let encoder_name: ObsString = self.encoder_id.clone().into();
138
139        let property_ptr = run_with_obs!(self.runtime, (encoder_name), move || {
140            let encoder_name_ptr = encoder_name.as_ptr().0;
141
142            let property_ptr = unsafe {
143                // Safety: encoder_name_ptr is valid because it comes from ObsString
144                libobs::obs_get_encoder_properties(encoder_name_ptr)
145            };
146
147            if property_ptr.is_null() {
148                Err(ObsError::NullPointer(None))
149            } else {
150                Ok(Sendable(property_ptr))
151            }
152        })??;
153
154        let drop_guard = Arc::new(_ObsPropertiesDropGuard::new(
155            property_ptr.clone(),
156            self.runtime.clone(),
157        ));
158
159        Ok(SmartPointerSendable::new(property_ptr.0, drop_guard))
160    }
161
162    fn get_properties_by_id_raw<T: Into<ObsString> + Sync + Send>(
163        id: T,
164        runtime: ObsRuntime,
165    ) -> Result<SmartPointerSendable<*mut libobs::obs_properties_t>, ObsError> {
166        let id: ObsString = id.into();
167        let ptr = run_with_obs!(runtime, (id), move || {
168            let id_ptr = id.as_ptr();
169
170            let property_ptr = unsafe {
171                // Safety: id_ptr is valid because it comes from ObsString
172                libobs::obs_get_encoder_properties(id_ptr.0)
173            };
174
175            if property_ptr.is_null() {
176                Err(ObsError::NullPointer(None))
177            } else {
178                Ok(Sendable(property_ptr))
179            }
180        })??;
181
182        let drop_guard = Arc::new(_ObsPropertiesDropGuard::new(ptr.clone(), runtime.clone()));
183
184        Ok(SmartPointerSendable::new(ptr.0, drop_guard))
185    }
186}