libobs_wrapper\encoders/
mod.rs

1use crate::{
2    context::ObsContext,
3    enums::{ObsEncoderType, OsEnumType},
4    run_with_obs,
5    runtime::ObsRuntime,
6    utils::{ObsError, ENCODER_HIDE_FLAGS},
7};
8use std::{ffi::CStr, os::raw::c_char};
9
10pub mod audio;
11mod enums;
12mod property_helper;
13pub use property_helper::*;
14pub mod video;
15pub use enums::*;
16
17pub trait ObsContextEncoders {
18    fn best_video_encoder(&self) -> Result<ObsVideoEncoderBuilder, ObsError>;
19
20    fn best_audio_encoder(&self) -> Result<ObsAudioEncoderBuilder, ObsError>;
21
22    fn available_audio_encoders(&self) -> Result<Vec<ObsAudioEncoderBuilder>, ObsError>;
23
24    fn available_video_encoders(&self) -> Result<Vec<ObsVideoEncoderBuilder>, ObsError>;
25}
26
27fn get_encoders_raw(
28    encoder_type: ObsEncoderType,
29    runtime: &ObsRuntime,
30) -> Result<Vec<String>, ObsError> {
31    let type_primitive = encoder_type as OsEnumType;
32
33    run_with_obs!(runtime, move || {
34        let mut n = 0;
35        let mut encoders = Vec::new();
36
37        let mut ptr: *const c_char = unsafe { std::mem::zeroed() };
38        while unsafe { libobs::obs_enum_encoder_types(n, &mut ptr) } {
39            n += 1;
40            let cstring = unsafe { CStr::from_ptr(ptr) };
41            if let Ok(enc) = cstring.to_str() {
42                unsafe {
43                    let is_hidden = libobs::obs_get_encoder_caps(ptr) & ENCODER_HIDE_FLAGS != 0;
44                    if is_hidden || libobs::obs_get_encoder_type(ptr) != type_primitive {
45                        continue;
46                    }
47                }
48
49                log::debug!("Found encoder: {}", enc);
50                encoders.push(enc.into());
51            }
52        }
53
54        encoders.sort_unstable();
55        encoders
56    })
57}
58
59impl ObsContextEncoders for ObsContext {
60    fn best_video_encoder(&self) -> Result<ObsVideoEncoderBuilder, ObsError> {
61        let encoders = self.available_video_encoders()?;
62        encoders
63            .into_iter()
64            .next()
65            .ok_or(ObsError::NoAvailableEncoders)
66    }
67
68    fn best_audio_encoder(&self) -> Result<ObsAudioEncoderBuilder, ObsError> {
69        let encoders = self.available_audio_encoders()?;
70        encoders
71            .into_iter()
72            .next()
73            .ok_or(ObsError::NoAvailableEncoders)
74    }
75
76    fn available_audio_encoders(&self) -> Result<Vec<ObsAudioEncoderBuilder>, ObsError> {
77        Ok(get_encoders_raw(ObsEncoderType::Audio, &self.runtime)?
78            .into_iter()
79            .map(|x| ObsAudioEncoderBuilder::new(self.clone(), &x))
80            .collect::<Vec<_>>())
81    }
82
83    fn available_video_encoders(&self) -> Result<Vec<ObsVideoEncoderBuilder>, ObsError> {
84        Ok(get_encoders_raw(ObsEncoderType::Video, &self.runtime)?
85            .into_iter()
86            .map(|x| ObsVideoEncoderBuilder::new(self.clone(), &x))
87            .collect::<Vec<_>>())
88    }
89}