libobs_wrapper\scenes/
filter_traits.rs

1use crate::data::object::ObsObjectTrait;
2use crate::run_with_obs;
3use crate::scenes::ObsSceneRef;
4use crate::sources::ObsFilterGuardPair;
5use crate::sources::ObsFilterRef;
6use crate::sources::_ObsRemoveFilterOnDrop;
7use crate::unsafe_send::SmartPointerSendable;
8use crate::utils::ObsError;
9use std::sync::Arc;
10
11pub trait ObsSceneExtFilter {
12    /// Adds a filter to the given source in this scene.
13    fn add_scene_filter(&self, filter_ref: &ObsFilterRef) -> Result<(), ObsError>;
14
15    /// Removes a filter from the this scene (internally removes the filter to the scene's source).
16    fn remove_scene_filter(&self, filter_ref: &ObsFilterRef) -> Result<(), ObsError>;
17}
18
19impl ObsSceneExtFilter for ObsSceneRef {
20    fn add_scene_filter(&self, filter_ref: &ObsFilterRef) -> Result<(), ObsError> {
21        let source_ptr = self.get_scene_source_ptr()?;
22        let filter_ptr = filter_ref.as_ptr();
23
24        let mut guard = self.attached_filters.write().map_err(|_| {
25            ObsError::LockError("Failed to acquire write lock on attached filters".into())
26        })?;
27
28        run_with_obs!(self.runtime, (source_ptr, filter_ptr), move || {
29            unsafe {
30                // Safety: Both source_ptr and filter_ptr are valid because of SmartPointers
31                libobs::obs_source_filter_add(source_ptr.0, filter_ptr.get_ptr());
32            };
33        })?;
34
35        let drop_guard = _ObsRemoveFilterOnDrop::new(
36            // We are using a no-op drop guard, because we are keeping the actual scene alive in the additional variable field
37            SmartPointerSendable::new(source_ptr.0, Arc::new(super::_NoOpDropGuard)),
38            filter_ref.as_ptr(),
39            Some(self.as_ptr()),
40            self.runtime.clone(),
41        );
42
43        guard.push(ObsFilterGuardPair::new(
44            filter_ref.clone(),
45            Arc::new(drop_guard),
46        ));
47
48        Ok(())
49    }
50
51    fn remove_scene_filter(&self, filter_ref: &ObsFilterRef) -> Result<(), ObsError> {
52        self.attached_filters
53            .write()
54            .map_err(|_| {
55                ObsError::LockError("Failed to acquire write lock on attached filters".into())
56            })?
57            .retain(|f| {
58                // Keep everything except this one filter
59                f.get_inner().as_ptr().get_ptr() != filter_ref.as_ptr().get_ptr()
60            });
61        Ok(())
62    }
63}