libobs_wrapper\encoders/
video.rs

1use libobs::{obs_encoder, video_output};
2use std::{ptr, sync::Arc};
3
4use crate::{
5    data::ObsData,
6    impl_obs_drop, run_with_obs,
7    runtime::ObsRuntime,
8    unsafe_send::Sendable,
9    utils::{ObsError, ObsString, VideoEncoderInfo},
10};
11
12#[derive(Debug)]
13#[allow(dead_code)]
14pub struct ObsVideoEncoder {
15    pub(crate) encoder: Sendable<*mut obs_encoder>,
16    pub(crate) id: ObsString,
17    pub(crate) name: ObsString,
18    pub(crate) settings: Option<ObsData>,
19    pub(crate) hotkey_data: Option<ObsData>,
20    pub(crate) runtime: ObsRuntime,
21}
22
23impl ObsVideoEncoder {
24    /// Info: the handler attribute is no longer needed and kept for compatibility. The `handler` parameter will be removed in a future release.
25    pub fn new_from_info(
26        info: VideoEncoderInfo,
27        runtime: ObsRuntime,
28    ) -> Result<Arc<Self>, ObsError> {
29        let settings_ptr = match &info.settings {
30            Some(x) => x.as_ptr(),
31            None => Sendable(ptr::null_mut()),
32        };
33
34        let hotkey_data_ptr = match &info.hotkey_data {
35            Some(x) => x.as_ptr(),
36            None => Sendable(ptr::null_mut()),
37        };
38
39        let id_ptr = info.id.as_ptr();
40        let name_ptr = info.name.as_ptr();
41        let encoder = run_with_obs!(
42            runtime,
43            (id_ptr, name_ptr, hotkey_data_ptr, settings_ptr),
44            move || unsafe {
45                let ptr = libobs::obs_video_encoder_create(
46                    id_ptr,
47                    name_ptr,
48                    settings_ptr,
49                    hotkey_data_ptr,
50                );
51                Sendable(ptr)
52            }
53        )?;
54
55        if encoder.0.is_null() {
56            return Err(ObsError::NullPointer);
57        }
58
59        Ok(Arc::new(Self {
60            encoder,
61            id: info.id,
62            name: info.name,
63            settings: info.settings,
64            hotkey_data: info.hotkey_data,
65            runtime,
66        }))
67    }
68
69    pub fn as_ptr(&self) -> Sendable<*mut obs_encoder> {
70        self.encoder.clone()
71    }
72
73    /// This is only needed once for global video context
74    pub fn set_video_context(
75        &mut self,
76        handler: Sendable<*mut video_output>,
77    ) -> Result<(), ObsError> {
78        let self_ptr = self.as_ptr();
79        run_with_obs!(self.runtime, (handler, self_ptr), move || unsafe {
80            libobs::obs_encoder_set_video(self_ptr, handler);
81        })
82    }
83
84    pub fn is_active(&self) -> Result<bool, ObsError> {
85        let encoder_ptr = self.as_ptr();
86
87        run_with_obs!(self.runtime, (encoder_ptr), move || unsafe {
88            libobs::obs_encoder_active(encoder_ptr)
89        })
90    }
91
92    pub fn update_settings(&mut self, settings: &ObsData) -> Result<(), ObsError> {
93        let encoder_ptr = self.as_ptr();
94        if self.is_active()? {
95            return Err(ObsError::EncoderActive);
96        }
97
98        let settings_ptr = settings.as_ptr();
99
100        run_with_obs!(self.runtime, (encoder_ptr, settings_ptr), move || unsafe {
101            libobs::obs_encoder_update(encoder_ptr, settings_ptr);
102        })
103    }
104}
105
106impl_obs_drop!(ObsVideoEncoder, (encoder), move || unsafe {
107    libobs::obs_encoder_release(encoder);
108});