libobs_wrapper\encoders/
video.rs1use libobs::{obs_encoder, video_output};
2use std::{
3 ptr,
4 sync::{Arc, RwLock},
5};
6
7use crate::{
8 data::{
9 object::{inner_fn_update_settings, ObsObjectTrait, ObsObjectTraitPrivate},
10 ImmutableObsData, ObsData, ObsDataPointers,
11 },
12 encoders::{_ObsEncoderDropGuard, ObsEncoderTrait},
13 run_with_obs,
14 runtime::ObsRuntime,
15 unsafe_send::{Sendable, SmartPointerSendable},
16 utils::{ObsError, ObsString, VideoEncoderInfo},
17};
18
19#[derive(Clone, Debug)]
20#[allow(dead_code)]
21pub struct ObsVideoEncoder {
27 pub(crate) id: ObsString,
28 pub(crate) name: ObsString,
29 pub(crate) settings: Arc<RwLock<ImmutableObsData>>,
30 pub(crate) hotkey_data: Arc<RwLock<ImmutableObsData>>,
31 pub(crate) runtime: ObsRuntime,
32 pub(crate) encoder: SmartPointerSendable<*mut obs_encoder>,
33}
34
35impl ObsVideoEncoder {
36 pub fn new_from_info(
38 info: VideoEncoderInfo,
39 runtime: ObsRuntime,
40 ) -> Result<Arc<Self>, ObsError> {
41 let VideoEncoderInfo {
42 id,
43 name,
44 settings,
45 hotkey_data,
46 } = info;
47
48 let settings_ptr = settings.as_ref().map(|s| s.as_ptr());
49 let hotkey_data_ptr = hotkey_data.as_ref().map(|h| h.as_ptr());
50
51 let encoder_ptr = run_with_obs!(
52 runtime,
53 (id, name, hotkey_data_ptr, settings_ptr),
54 move || {
55 let settings_ptr_raw = match settings_ptr {
56 Some(s) => s.get_ptr(),
57 None => ptr::null_mut(),
58 };
59
60 let hotkey_data_ptr_raw = match hotkey_data_ptr {
61 Some(h) => h.get_ptr(),
62 None => ptr::null_mut(),
63 };
64
65 let ptr = unsafe {
66 libobs::obs_video_encoder_create(
68 id.as_ptr().0,
69 name.as_ptr().0,
70 settings_ptr_raw,
71 hotkey_data_ptr_raw,
72 )
73 };
74
75 if ptr.is_null() {
76 Err(ObsError::NullPointer(None))
77 } else {
78 Ok(Sendable(ptr))
79 }
80 }
81 )??;
82
83 let encoder_ptr = SmartPointerSendable::new(
84 encoder_ptr.0,
85 Arc::new(_ObsEncoderDropGuard {
86 encoder: encoder_ptr,
87 runtime: runtime.clone(),
88 }),
89 runtime.native_registry(),
90 );
91
92 let hotkey_data = match hotkey_data {
93 Some(h) => h,
94 None => ImmutableObsData::new(&runtime)?,
95 };
96
97 let settings = {
98 let settings_ptr = run_with_obs!(runtime, (encoder_ptr), move || {
99 let ptr = unsafe {
100 libobs::obs_encoder_get_settings(encoder_ptr.get_ptr())
102 };
103
104 Sendable(ptr)
105 })?;
106 ImmutableObsData::from_raw_pointer(settings_ptr, runtime.clone())
107 };
108
109 Ok(Arc::new(Self {
110 encoder: encoder_ptr,
111 id,
112 name,
113 settings: Arc::new(RwLock::new(settings)),
114 hotkey_data: Arc::new(RwLock::new(hotkey_data)),
115 runtime,
116 }))
117 }
118
119 pub unsafe fn set_video_context(&self, handler: *mut video_output) -> Result<(), ObsError> {
123 let handler = Sendable(handler);
124 let self_ptr = self.__native_handle();
125 run_with_obs!(self.runtime, (handler, self_ptr), move || {
126 unsafe {
127 libobs::obs_encoder_set_video(self_ptr.get_ptr(), handler.0);
129 }
130 })
131 }
132}
133
134impl ObsObjectTraitPrivate for ObsVideoEncoder {
135 fn __internal_replace_settings(&self, settings: ImmutableObsData) -> Result<(), ObsError> {
136 self.settings
137 .write()
138 .map_err(|_| {
139 ObsError::LockError(
140 "Failed to acquire lock for replacing settings in the video encoder".into(),
141 )
142 })
143 .map(|mut guard| {
144 *guard = settings;
145 })
146 }
147
148 fn __internal_replace_hotkey_data(
149 &self,
150 hotkey_data: ImmutableObsData,
151 ) -> Result<(), ObsError> {
152 self.hotkey_data
153 .write()
154 .map_err(|_| {
155 ObsError::LockError(
156 "Failed to acquire lock for replacing hotkey data in the video encoder".into(),
157 )
158 })
159 .map(|mut guard| {
160 *guard = hotkey_data;
161 })
162 }
163}
164
165impl ObsObjectTrait for ObsVideoEncoder {
166 type Native = *mut libobs::obs_encoder;
167
168 fn __native_handle(&self) -> SmartPointerSendable<Self::Native> {
169 self.encoder.clone()
170 }
171
172 fn runtime(&self) -> &ObsRuntime {
173 &self.runtime
174 }
175
176 fn settings(&self) -> Result<ImmutableObsData, ObsError> {
177 self.settings
178 .read()
179 .map_err(|_| {
180 ObsError::LockError(
181 "Failed to acquire lock for reading settings in the video encoder".into(),
182 )
183 })
184 .map(|s| s.clone())
185 }
186
187 fn hotkey_data(&self) -> Result<ImmutableObsData, ObsError> {
188 self.hotkey_data
189 .read()
190 .map_err(|_| {
191 ObsError::LockError(
192 "Failed to acquire lock for reading hotkey data in the video encoder".into(),
193 )
194 })
195 .map(|h| h.clone())
196 }
197
198 fn id(&self) -> ObsString {
199 self.id.clone()
200 }
201
202 fn name(&self) -> ObsString {
203 self.name.clone()
204 }
205
206 fn update_settings(&self, settings: ObsData) -> Result<(), ObsError> {
208 if self.is_active()? {
209 return Err(ObsError::EncoderActive);
210 }
211
212 inner_fn_update_settings!(self, libobs::obs_encoder_update, settings)
213 }
214}
215
216impl ObsEncoderTrait for ObsVideoEncoder {}