1use std::{boxed::Box, fmt::Debug, pin::Pin};
2
3use display_info::DisplayInfo;
4use libobs::obs_video_info;
5
6#[cfg(target_os = "linux")]
7use crate::utils::linux::get_linux_opengl_lib_name;
8use crate::{
9 enums::{
10 ObsColorspace, ObsGraphicsModule, ObsScaleType, ObsVideoFormat, ObsVideoRange, OsEnumType,
11 },
12 unsafe_send::Sendable,
13 utils::ObsString,
14};
15
16#[derive(Clone, Debug)]
17pub struct ObsSdrVideoInfo {
18 pub sdr_white_level: f32,
20 pub hdr_nominal_peak_level: f32,
22}
23
24impl Default for ObsSdrVideoInfo {
25 fn default() -> Self {
26 Self {
27 sdr_white_level: 300.0,
28 hdr_nominal_peak_level: 1000.0,
29 }
30 }
31}
32
33pub struct ObsVideoInfo {
43 ovi: Sendable<Pin<Box<obs_video_info>>>,
44 #[allow(dead_code)]
48 graphics_module: ObsString,
49
50 sdr_info: ObsSdrVideoInfo,
51}
52
53impl Debug for ObsVideoInfo {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.debug_struct("ObsVideoInfo")
56 .field("fps_num", &self.get_fps_num())
57 .field("fps_den", &self.get_fps_den())
58 .field("base_width", &self.get_base_width())
59 .field("base_height", &self.get_base_height())
60 .field("output_width", &self.get_output_width())
61 .field("output_height", &self.get_output_height())
62 .field("sdr_info", &self.get_sdr_info())
63 .finish()
64 }
65}
66
67impl ObsVideoInfo {
68 #[deprecated = "Use new_with_sdr_info or the ObsVideoInfoBuilder instead"]
75 pub fn new(ovi: obs_video_info, graphics_module: ObsString) -> Self {
76 Self {
77 ovi: Sendable(Box::pin(ovi)),
78 graphics_module,
79 sdr_info: ObsSdrVideoInfo::default(),
80 }
81 }
82
83 pub fn new_with_sdr_info(
90 ovi: obs_video_info,
91 graphics_module: ObsString,
92 sdr_info: ObsSdrVideoInfo,
93 ) -> Self {
94 Self {
95 ovi: Sendable(Box::pin(ovi)),
96 graphics_module,
97 sdr_info,
98 }
99 }
100
101 pub fn as_ptr(&self) -> *mut obs_video_info {
103 let ptr: *const obs_video_info = &*Pin::as_ref(&self.ovi.0);
105 ptr as *mut obs_video_info
106 }
107
108 pub fn graphics_module(&self) -> &ObsString {
109 &self.graphics_module
110 }
111
112 pub fn get_fps_num(&self) -> u32 {
113 self.ovi.0.fps_num
114 }
115
116 pub fn get_fps_den(&self) -> u32 {
117 self.ovi.0.fps_den
118 }
119
120 pub fn get_base_width(&self) -> u32 {
121 self.ovi.0.base_width
122 }
123
124 pub fn get_base_height(&self) -> u32 {
125 self.ovi.0.base_height
126 }
127
128 pub fn get_output_width(&self) -> u32 {
129 self.ovi.0.output_width
130 }
131
132 pub fn get_output_height(&self) -> u32 {
133 self.ovi.0.output_height
134 }
135
136 pub fn get_sdr_info(&self) -> &ObsSdrVideoInfo {
137 &self.sdr_info
138 }
139}
140
141impl Default for ObsVideoInfo {
142 fn default() -> Self {
143 ObsVideoInfoBuilder::new().build()
144 }
145}
146
147#[derive(Clone, Debug)]
152pub struct ObsVideoInfoBuilder {
153 adapter: u32,
154 graphics_module: ObsGraphicsModule,
155 fps_num: u32,
156 fps_den: u32,
157 base_width: u32,
158 base_height: u32,
159 output_width: u32,
160 output_height: u32,
161 output_format: ObsVideoFormat,
162 gpu_conversion: bool,
163 colorspace: ObsColorspace,
164 range: ObsVideoRange,
165 scale_type: ObsScaleType,
166 sdr_info: ObsSdrVideoInfo,
167}
168
169impl ObsVideoInfoBuilder {
170 pub fn new() -> Self {
181 let display_infos = DisplayInfo::all().unwrap_or_default();
182 let (mut width, mut height) = (1920, 1080);
183 for display_info in display_infos {
184 if display_info.is_primary {
185 width = display_info.width;
186 height = display_info.height;
187 break;
188 }
189 }
190
191 Self {
192 adapter: 0,
193 #[cfg(target_family = "unix")]
194 graphics_module: ObsGraphicsModule::OpenGL,
195 #[cfg(target_family = "windows")]
196 graphics_module: ObsGraphicsModule::DirectX11,
197 fps_num: 30,
198 fps_den: 1,
199 base_width: width,
200 base_height: height,
201 output_width: width,
202 output_height: height,
203 output_format: ObsVideoFormat::NV12,
204 gpu_conversion: true,
205 colorspace: ObsColorspace::CS709,
206 range: ObsVideoRange::Default,
207 scale_type: ObsScaleType::Lanczos,
208 sdr_info: ObsSdrVideoInfo::default(),
209 }
210 }
211
212 pub fn build(self) -> ObsVideoInfo {
215 let graphics_mod_str = match self.graphics_module {
216 #[cfg(not(target_os = "linux"))]
217 ObsGraphicsModule::OpenGL => ObsString::new("libobs-opengl"),
218 #[cfg(target_os = "linux")]
219 ObsGraphicsModule::OpenGL => ObsString::new(get_linux_opengl_lib_name()),
220 ObsGraphicsModule::DirectX11 => ObsString::new("libobs-d3d11.dll"),
221 };
222
223 let ovi = obs_video_info {
224 adapter: self.adapter,
225 graphics_module: graphics_mod_str.as_ptr().0,
226 fps_num: self.fps_num,
227 fps_den: self.fps_den,
228 base_width: self.base_width,
229 base_height: self.base_height,
230 output_width: self.output_width,
231 output_height: self.output_height,
232 output_format: self.output_format as OsEnumType,
233 gpu_conversion: self.gpu_conversion,
234 colorspace: self.colorspace as OsEnumType,
235 range: self.range as OsEnumType,
236 scale_type: self.scale_type as OsEnumType,
237 };
238
239 ObsVideoInfo {
240 ovi: Sendable(Box::pin(ovi)),
241 graphics_module: graphics_mod_str,
242 sdr_info: self.sdr_info,
243 }
244 }
245
246 pub fn set_sdr_info(mut self, sdr_info: ObsSdrVideoInfo) -> Self {
247 self.sdr_info = sdr_info;
248 self
249 }
250
251 pub fn adapter(mut self, value: u32) -> Self {
255 self.adapter = value;
256 self
257 }
258
259 pub fn graphics_module(mut self, value: ObsGraphicsModule) -> Self {
262 self.graphics_module = value;
263 self
264 }
265
266 pub fn fps_num(mut self, value: u32) -> Self {
272 self.fps_num = value;
273 self
274 }
275
276 pub fn fps_den(mut self, value: u32) -> Self {
280 self.fps_den = value;
281 self
282 }
283
284 pub fn base_width(mut self, value: u32) -> Self {
287 self.base_width = value;
288 self
289 }
290
291 pub fn base_height(mut self, value: u32) -> Self {
294 self.base_height = value;
295 self
296 }
297
298 pub fn output_width(mut self, value: u32) -> Self {
301 self.output_width = value;
302 self
303 }
304
305 pub fn output_height(mut self, value: u32) -> Self {
308 self.output_height = value;
309 self
310 }
311
312 pub fn output_format(mut self, value: ObsVideoFormat) -> Self {
315 self.output_format = value;
316 self
317 }
318
319 pub fn gpu_conversion(mut self, value: bool) -> Self {
322 self.gpu_conversion = value;
323 self
324 }
325
326 pub fn colorspace(mut self, value: ObsColorspace) -> Self {
328 self.colorspace = value;
329 self
330 }
331
332 pub fn range(mut self, value: ObsVideoRange) -> Self {
334 self.range = value;
335 self
336 }
337
338 pub fn scale_type(mut self, value: ObsScaleType) -> Self {
340 self.scale_type = value;
341 self
342 }
343}
344
345#[cfg_attr(coverage_nightly, coverage(off))]
346impl Default for ObsVideoInfoBuilder {
347 fn default() -> Self {
348 Self::new()
349 }
350}