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 {
39 ovi: Sendable<Pin<Box<obs_video_info>>>,
40 #[allow(dead_code)]
44 graphics_module: ObsString,
45
46 sdr_info: ObsSdrVideoInfo,
47}
48
49impl Debug for ObsVideoInfo {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 f.debug_struct("ObsVideoInfo")
52 .field("fps_num", &self.get_fps_num())
53 .field("fps_den", &self.get_fps_den())
54 .field("base_width", &self.get_base_width())
55 .field("base_height", &self.get_base_height())
56 .field("output_width", &self.get_output_width())
57 .field("output_height", &self.get_output_height())
58 .field("sdr_info", &self.get_sdr_info())
59 .finish()
60 }
61}
62
63impl ObsVideoInfo {
64 #[deprecated = "Use new_with_sdr_info or the ObsVideoInfoBuilder instead"]
71 pub fn new(ovi: obs_video_info, graphics_module: ObsString) -> Self {
72 Self {
73 ovi: Sendable(Box::pin(ovi)),
74 graphics_module,
75 sdr_info: ObsSdrVideoInfo::default(),
76 }
77 }
78
79 pub fn new_with_sdr_info(
86 ovi: obs_video_info,
87 graphics_module: ObsString,
88 sdr_info: ObsSdrVideoInfo,
89 ) -> Self {
90 Self {
91 ovi: Sendable(Box::pin(ovi)),
92 graphics_module,
93 sdr_info,
94 }
95 }
96
97 pub fn as_ptr(&self) -> *mut obs_video_info {
99 let ptr: *const obs_video_info = &*Pin::as_ref(&self.ovi.0);
101 ptr as *mut obs_video_info
102 }
103
104 pub fn graphics_module(&self) -> &ObsString {
105 &self.graphics_module
106 }
107
108 pub fn get_fps_num(&self) -> u32 {
109 self.ovi.0.fps_num
110 }
111
112 pub fn get_fps_den(&self) -> u32 {
113 self.ovi.0.fps_den
114 }
115
116 pub fn get_base_width(&self) -> u32 {
117 self.ovi.0.base_width
118 }
119
120 pub fn get_base_height(&self) -> u32 {
121 self.ovi.0.base_height
122 }
123
124 pub fn get_output_width(&self) -> u32 {
125 self.ovi.0.output_width
126 }
127
128 pub fn get_output_height(&self) -> u32 {
129 self.ovi.0.output_height
130 }
131
132 pub fn get_sdr_info(&self) -> &ObsSdrVideoInfo {
133 &self.sdr_info
134 }
135}
136
137impl Default for ObsVideoInfo {
138 fn default() -> Self {
139 ObsVideoInfoBuilder::new().build()
140 }
141}
142
143#[derive(Clone, Debug)]
148pub struct ObsVideoInfoBuilder {
149 adapter: u32,
150 graphics_module: ObsGraphicsModule,
151 fps_num: u32,
152 fps_den: u32,
153 base_width: u32,
154 base_height: u32,
155 output_width: u32,
156 output_height: u32,
157 output_format: ObsVideoFormat,
158 gpu_conversion: bool,
159 colorspace: ObsColorspace,
160 range: ObsVideoRange,
161 scale_type: ObsScaleType,
162 sdr_info: ObsSdrVideoInfo,
163}
164
165impl ObsVideoInfoBuilder {
166 pub fn new() -> Self {
177 let display_infos = DisplayInfo::all().unwrap_or_default();
178 let (mut width, mut height) = (1920, 1080);
179 for display_info in display_infos {
180 if display_info.is_primary {
181 width = display_info.width;
182 height = display_info.height;
183 break;
184 }
185 }
186
187 Self {
188 adapter: 0,
189 #[cfg(target_family = "unix")]
190 graphics_module: ObsGraphicsModule::OpenGL,
191 #[cfg(target_family = "windows")]
192 graphics_module: ObsGraphicsModule::DirectX11,
193 fps_num: 30,
194 fps_den: 1,
195 base_width: width,
196 base_height: height,
197 output_width: width,
198 output_height: height,
199 output_format: ObsVideoFormat::NV12,
200 gpu_conversion: true,
201 colorspace: ObsColorspace::CS709,
202 range: ObsVideoRange::Default,
203 scale_type: ObsScaleType::Lanczos,
204 sdr_info: ObsSdrVideoInfo::default(),
205 }
206 }
207
208 pub fn build(self) -> ObsVideoInfo {
211 let graphics_mod_str = match self.graphics_module {
212 #[cfg(not(target_os = "linux"))]
213 ObsGraphicsModule::OpenGL => ObsString::new("libobs-opengl"),
214 #[cfg(target_os = "linux")]
215 ObsGraphicsModule::OpenGL => ObsString::new(get_linux_opengl_lib_name()),
216 ObsGraphicsModule::DirectX11 => ObsString::new("libobs-d3d11.dll"),
217 };
218
219 let ovi = obs_video_info {
220 adapter: self.adapter,
221 graphics_module: graphics_mod_str.as_ptr().0,
222 fps_num: self.fps_num,
223 fps_den: self.fps_den,
224 base_width: self.base_width,
225 base_height: self.base_height,
226 output_width: self.output_width,
227 output_height: self.output_height,
228 output_format: self.output_format as OsEnumType,
229 gpu_conversion: self.gpu_conversion,
230 colorspace: self.colorspace as OsEnumType,
231 range: self.range as OsEnumType,
232 scale_type: self.scale_type as OsEnumType,
233 };
234
235 ObsVideoInfo {
236 ovi: Sendable(Box::pin(ovi)),
237 graphics_module: graphics_mod_str,
238 sdr_info: self.sdr_info,
239 }
240 }
241
242 pub fn set_sdr_info(mut self, sdr_info: ObsSdrVideoInfo) -> Self {
243 self.sdr_info = sdr_info;
244 self
245 }
246
247 pub fn adapter(mut self, value: u32) -> Self {
251 self.adapter = value;
252 self
253 }
254
255 pub fn graphics_module(mut self, value: ObsGraphicsModule) -> Self {
258 self.graphics_module = value;
259 self
260 }
261
262 pub fn fps_num(mut self, value: u32) -> Self {
268 self.fps_num = value;
269 self
270 }
271
272 pub fn fps_den(mut self, value: u32) -> Self {
276 self.fps_den = value;
277 self
278 }
279
280 pub fn base_width(mut self, value: u32) -> Self {
283 self.base_width = value;
284 self
285 }
286
287 pub fn base_height(mut self, value: u32) -> Self {
290 self.base_height = value;
291 self
292 }
293
294 pub fn output_width(mut self, value: u32) -> Self {
297 self.output_width = value;
298 self
299 }
300
301 pub fn output_height(mut self, value: u32) -> Self {
304 self.output_height = value;
305 self
306 }
307
308 pub fn output_format(mut self, value: ObsVideoFormat) -> Self {
311 self.output_format = value;
312 self
313 }
314
315 pub fn gpu_conversion(mut self, value: bool) -> Self {
318 self.gpu_conversion = value;
319 self
320 }
321
322 pub fn colorspace(mut self, value: ObsColorspace) -> Self {
324 self.colorspace = value;
325 self
326 }
327
328 pub fn range(mut self, value: ObsVideoRange) -> Self {
330 self.range = value;
331 self
332 }
333
334 pub fn scale_type(mut self, value: ObsScaleType) -> Self {
336 self.scale_type = value;
337 self
338 }
339}
340
341#[cfg_attr(coverage_nightly, coverage(off))]
342impl Default for ObsVideoInfoBuilder {
343 fn default() -> Self {
344 Self::new()
345 }
346}