libobs_wrapper\encoders/
mod.rs1use crate::{
9 context::ObsContext,
10 enums::{ObsEncoderType, OsEnumType},
11 impl_obs_drop, run_with_obs,
12 runtime::ObsRuntime,
13 unsafe_send::Sendable,
14 utils::{ObsDropGuard, ObsError, ENCODER_HIDE_FLAGS},
15};
16use std::{ffi::CStr, os::raw::c_char};
17
18pub mod audio;
19mod enums;
20mod traits;
21pub use traits::*;
22mod property_helper;
23pub use property_helper::*;
24pub mod video;
25pub use enums::*;
26
27pub trait ObsContextEncoders {
28 fn best_video_encoder(&self) -> Result<ObsVideoEncoderBuilder, ObsError>;
29
30 fn best_audio_encoder(&self) -> Result<ObsAudioEncoderBuilder, ObsError>;
31
32 fn available_audio_encoders(&self) -> Result<Vec<ObsAudioEncoderBuilder>, ObsError>;
33
34 fn available_video_encoders(&self) -> Result<Vec<ObsVideoEncoderBuilder>, ObsError>;
35}
36
37fn get_encoders_raw(
38 encoder_type: ObsEncoderType,
39 runtime: &ObsRuntime,
40) -> Result<Vec<String>, ObsError> {
41 let type_primitive = encoder_type as OsEnumType;
42
43 run_with_obs!(runtime, move || {
44 let mut n = 0;
45 let mut encoders = Vec::new();
46
47 let mut ptr: *const c_char = unsafe {
48 std::mem::zeroed()
51 };
52 while unsafe {
53 libobs::obs_enum_encoder_types(n, &mut ptr)
55 } {
56 n += 1;
57 if ptr.is_null() {
58 continue;
59 }
60
61 let cstring = unsafe {
62 CStr::from_ptr(ptr)
64 };
65 if let Ok(enc) = cstring.to_str() {
66 unsafe {
67 let is_hidden = libobs::obs_get_encoder_caps(ptr) & ENCODER_HIDE_FLAGS != 0;
69 if is_hidden || libobs::obs_get_encoder_type(ptr) != type_primitive {
70 continue;
71 }
72 }
73
74 log::debug!("Found encoder: {}", enc);
75 encoders.push(enc.into());
76 }
77 }
78
79 encoders.sort_unstable();
80 encoders
81 })
82}
83
84impl ObsContextEncoders for ObsContext {
85 fn best_video_encoder(&self) -> Result<ObsVideoEncoderBuilder, ObsError> {
86 let encoders = self.available_video_encoders()?;
87 encoders
88 .into_iter()
89 .next()
90 .ok_or(ObsError::NoAvailableEncoders)
91 }
92
93 fn best_audio_encoder(&self) -> Result<ObsAudioEncoderBuilder, ObsError> {
94 let encoders = self.available_audio_encoders()?;
95 encoders
96 .into_iter()
97 .next()
98 .ok_or(ObsError::NoAvailableEncoders)
99 }
100
101 fn available_audio_encoders(&self) -> Result<Vec<ObsAudioEncoderBuilder>, ObsError> {
102 Ok(get_encoders_raw(ObsEncoderType::Audio, self.runtime())?
103 .into_iter()
104 .map(|x| ObsAudioEncoderBuilder::new(self.clone(), &x))
105 .collect::<Vec<_>>())
106 }
107
108 fn available_video_encoders(&self) -> Result<Vec<ObsVideoEncoderBuilder>, ObsError> {
109 Ok(get_encoders_raw(ObsEncoderType::Video, self.runtime())?
110 .into_iter()
111 .map(|x| ObsVideoEncoderBuilder::new(self.clone(), &x))
112 .collect::<Vec<_>>())
113 }
114}
115
116#[derive(Debug)]
117pub(super) struct _ObsEncoderDropGuard {
118 encoder: Sendable<*mut libobs::obs_encoder_t>,
119 runtime: ObsRuntime,
120}
121
122impl ObsDropGuard for _ObsEncoderDropGuard {}
123
124impl_obs_drop!(_ObsEncoderDropGuard, (encoder), move || unsafe {
125 libobs::obs_encoder_release(encoder.0);
127});