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 {
30 #[deprecated = "Use ObsContext::capabilities()?.select_video_encoder()"]
31 fn best_video_encoder(&self) -> Result<ObsVideoEncoderBuilder, ObsError>;
32
33 #[deprecated = "Use ObsContext::capabilities()?.select_audio_encoder()"]
34 fn best_audio_encoder(&self) -> Result<ObsAudioEncoderBuilder, ObsError>;
35
36 #[deprecated = "Use ObsContext::capabilities()?.select_audio_encoder().matches()"]
37 fn available_audio_encoders(&self) -> Result<Vec<ObsAudioEncoderBuilder>, ObsError>;
38
39 #[deprecated = "Use ObsContext::capabilities()?.select_video_encoder().matches()"]
40 fn available_video_encoders(&self) -> Result<Vec<ObsVideoEncoderBuilder>, ObsError>;
41}
42
43fn get_encoders_raw(
44 encoder_type: ObsEncoderType,
45 runtime: &ObsRuntime,
46) -> Result<Vec<String>, ObsError> {
47 let type_primitive = encoder_type as OsEnumType;
48
49 run_with_obs!(runtime, move || {
50 let mut n = 0;
51 let mut encoders = Vec::new();
52
53 let mut ptr: *const c_char = unsafe {
54 std::mem::zeroed()
57 };
58 while unsafe {
59 libobs::obs_enum_encoder_types(n, &mut ptr)
61 } {
62 n += 1;
63 if ptr.is_null() {
64 continue;
65 }
66
67 let cstring = unsafe {
68 CStr::from_ptr(ptr)
70 };
71 if let Ok(enc) = cstring.to_str() {
72 unsafe {
73 let is_hidden = libobs::obs_get_encoder_caps(ptr) & ENCODER_HIDE_FLAGS != 0;
75 if is_hidden || libobs::obs_get_encoder_type(ptr) != type_primitive {
76 continue;
77 }
78 }
79
80 log::debug!("Found encoder: {}", enc);
81 encoders.push(enc.into());
82 }
83 }
84
85 encoders.sort_unstable();
86 encoders
87 })
88}
89
90impl ObsContextEncoders for ObsContext {
91 fn best_video_encoder(&self) -> Result<ObsVideoEncoderBuilder, ObsError> {
92 get_encoders_raw(ObsEncoderType::Video, self.runtime())?
93 .into_iter()
94 .next()
95 .map(|id| ObsVideoEncoderBuilder::new(self.clone(), &id))
96 .ok_or(ObsError::NoAvailableEncoders)
97 }
98
99 fn best_audio_encoder(&self) -> Result<ObsAudioEncoderBuilder, ObsError> {
100 get_encoders_raw(ObsEncoderType::Audio, self.runtime())?
101 .into_iter()
102 .next()
103 .map(|id| ObsAudioEncoderBuilder::new(self.clone(), &id))
104 .ok_or(ObsError::NoAvailableEncoders)
105 }
106
107 fn available_audio_encoders(&self) -> Result<Vec<ObsAudioEncoderBuilder>, ObsError> {
108 Ok(get_encoders_raw(ObsEncoderType::Audio, self.runtime())?
109 .into_iter()
110 .map(|x| ObsAudioEncoderBuilder::new(self.clone(), &x))
111 .collect::<Vec<_>>())
112 }
113
114 fn available_video_encoders(&self) -> Result<Vec<ObsVideoEncoderBuilder>, ObsError> {
115 Ok(get_encoders_raw(ObsEncoderType::Video, self.runtime())?
116 .into_iter()
117 .map(|x| ObsVideoEncoderBuilder::new(self.clone(), &x))
118 .collect::<Vec<_>>())
119 }
120}
121
122#[derive(Debug)]
123pub(super) struct _ObsEncoderDropGuard {
124 encoder: Sendable<*mut libobs::obs_encoder_t>,
125 runtime: ObsRuntime,
126}
127
128impl ObsDropGuard for _ObsEncoderDropGuard {}
129
130impl_obs_drop!(_ObsEncoderDropGuard, (encoder), move || unsafe {
131 libobs::obs_encoder_release(encoder.0);
133});