Skip to main content

libobs_wrapper\scenes/
filter_traits.rs

1use crate::data::object::ObsObjectTrait;
2use crate::run_with_obs;
3use crate::scenes::ObsSceneRef;
4use crate::sources::_ObsRemoveFilterOnDrop;
5use crate::sources::ObsFilterGuardPair;
6use crate::sources::ObsFilterRef;
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        self.runtime.ensure_same_runtime(filter_ref.runtime())?;
22        let source_ptr = self.get_scene_source_ptr()?;
23        let filter_ptr = filter_ref.__native_handle();
24
25        let mut guard = self.attached_filters.write().map_err(|_| {
26            ObsError::LockError("Failed to acquire write lock on attached filters".into())
27        })?;
28
29        run_with_obs!(self.runtime, (source_ptr, filter_ptr), move || {
30            unsafe {
31                // Safety: Both source_ptr and filter_ptr are valid because of SmartPointers
32                libobs::obs_source_filter_add(source_ptr.0, filter_ptr.get_ptr());
33            };
34        })?;
35
36        let drop_guard = _ObsRemoveFilterOnDrop::new(
37            // We are using a no-op drop guard, because we are keeping the actual scene alive in the additional variable field
38            SmartPointerSendable::new(
39                source_ptr.0,
40                Arc::new(super::_NoOpDropGuard),
41                self.runtime.native_registry(),
42            ),
43            filter_ref.__native_handle(),
44            Some(self.as_ptr()),
45            self.runtime.clone(),
46        );
47
48        guard.push(ObsFilterGuardPair::new(
49            filter_ref.clone(),
50            Arc::new(drop_guard),
51        ));
52
53        Ok(())
54    }
55
56    fn remove_scene_filter(&self, filter_ref: &ObsFilterRef) -> Result<(), ObsError> {
57        self.runtime.ensure_same_runtime(filter_ref.runtime())?;
58        self.attached_filters
59            .write()
60            .map_err(|_| {
61                ObsError::LockError("Failed to acquire write lock on attached filters".into())
62            })?
63            .retain(|f| {
64                // Keep everything except this one filter
65                f.get_inner().__native_handle().native_id()
66                    != filter_ref.__native_handle().native_id()
67            });
68        Ok(())
69    }
70}