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::{ObsEncoderTrait, _ObsEncoderDropGuard},
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 );
90
91 let hotkey_data = match hotkey_data {
92 Some(h) => h,
93 None => ImmutableObsData::new(&runtime)?,
94 };
95
96 let settings = {
97 let settings_ptr = run_with_obs!(runtime, (encoder_ptr), move || {
98 let ptr = unsafe {
99 libobs::obs_encoder_get_settings(encoder_ptr.get_ptr())
101 };
102
103 Sendable(ptr)
104 })?;
105 ImmutableObsData::from_raw_pointer(settings_ptr, runtime.clone())
106 };
107
108 Ok(Arc::new(Self {
109 encoder: encoder_ptr,
110 id,
111 name,
112 settings: Arc::new(RwLock::new(settings)),
113 hotkey_data: Arc::new(RwLock::new(hotkey_data)),
114 runtime,
115 }))
116 }
117
118 pub unsafe fn set_video_context(
122 &mut self,
123 handler: Sendable<*mut video_output>,
124 ) -> Result<(), ObsError> {
125 let self_ptr = self.as_ptr();
126 run_with_obs!(self.runtime, (handler, self_ptr), move || {
127 unsafe {
128 libobs::obs_encoder_set_video(self_ptr.get_ptr(), handler.0);
130 }
131 })
132 }
133}
134
135impl ObsObjectTraitPrivate for ObsVideoEncoder {
136 fn __internal_replace_settings(&self, settings: ImmutableObsData) -> Result<(), ObsError> {
137 self.settings
138 .write()
139 .map_err(|_| {
140 ObsError::LockError(
141 "Failed to acquire lock for replacing settings in the video encoder".into(),
142 )
143 })
144 .map(|mut guard| {
145 *guard = settings;
146 })
147 }
148
149 fn __internal_replace_hotkey_data(
150 &self,
151 hotkey_data: ImmutableObsData,
152 ) -> Result<(), ObsError> {
153 self.hotkey_data
154 .write()
155 .map_err(|_| {
156 ObsError::LockError(
157 "Failed to acquire lock for replacing hotkey data in the video encoder".into(),
158 )
159 })
160 .map(|mut guard| {
161 *guard = hotkey_data;
162 })
163 }
164}
165
166impl ObsObjectTrait<*mut libobs::obs_encoder> for ObsVideoEncoder {
167 fn runtime(&self) -> &ObsRuntime {
168 &self.runtime
169 }
170
171 fn settings(&self) -> Result<ImmutableObsData, ObsError> {
172 self.settings
173 .read()
174 .map_err(|_| {
175 ObsError::LockError(
176 "Failed to acquire lock for reading settings in the video encoder".into(),
177 )
178 })
179 .map(|s| s.clone())
180 }
181
182 fn hotkey_data(&self) -> Result<ImmutableObsData, ObsError> {
183 self.hotkey_data
184 .read()
185 .map_err(|_| {
186 ObsError::LockError(
187 "Failed to acquire lock for reading hotkey data in the video encoder".into(),
188 )
189 })
190 .map(|h| h.clone())
191 }
192
193 fn id(&self) -> ObsString {
194 self.id.clone()
195 }
196
197 fn name(&self) -> ObsString {
198 self.name.clone()
199 }
200
201 fn update_settings(&self, settings: ObsData) -> Result<(), ObsError> {
203 if self.is_active()? {
204 return Err(ObsError::EncoderActive);
205 }
206
207 inner_fn_update_settings!(self, libobs::obs_encoder_update, settings)
208 }
209
210 fn as_ptr(&self) -> SmartPointerSendable<*mut obs_encoder> {
211 self.encoder.clone()
212 }
213}
214
215impl ObsEncoderTrait for ObsVideoEncoder {}