waycap_rs/encoders/
dynamic_encoder.rs1use crossbeam::channel::Receiver;
2use ffmpeg_next::codec::encoder;
3
4use crate::{
5 encoders::video::{PipewireSPA, ProcessingThread},
6 types::{
7 config::VideoEncoder as VideoEncoderType,
8 error::Result,
9 video_frame::{EncodedVideoFrame, RawVideoFrame},
10 },
11 VideoEncoder,
12};
13
14#[cfg(feature = "vaapi")]
15use crate::encoders::vaapi_encoder::VaapiEncoder;
16
17#[cfg(feature = "nvidia")]
18use crate::encoders::nvenc_encoder::NvencEncoder;
19#[cfg(all(feature = "vaapi", feature = "nvidia"))]
20use crate::types::error::WaycapError;
21
22#[cfg(all(feature = "vaapi", feature = "nvidia", feature = "vulkan"))]
24use crate::waycap_vulkan::{detect_gpu_vendor, GpuVendor};
25#[cfg(all(feature = "vaapi", feature = "nvidia", feature = "egl"))]
26use crate::waycap_egl::{detect_gpu_vendor, GpuVendor};
27
28pub enum DynamicEncoder {
29 #[cfg(feature = "vaapi")]
30 Vaapi(VaapiEncoder),
31 #[cfg(feature = "nvidia")]
32 Nvenc(NvencEncoder),
33}
34
35impl DynamicEncoder {
36 pub(crate) fn new(
37 encoder_type: Option<VideoEncoderType>,
38 width: u32,
39 height: u32,
40 quality_preset: crate::types::config::QualityPreset,
41 ) -> crate::types::error::Result<DynamicEncoder> {
42 let encoder_type = match encoder_type {
43 Some(typ) => typ,
44 #[cfg(all(feature = "vaapi", feature = "nvidia"))]
46 None => match detect_gpu_vendor()? {
47 GpuVendor::NVIDIA => VideoEncoderType::H264Nvenc,
48 GpuVendor::AMD | GpuVendor::INTEL => VideoEncoderType::H264Vaapi,
49 GpuVendor::UNKNOWN => {
50 return Err(WaycapError::Init(
51 "Unknown/Unimplemented GPU vendor".to_string(),
52 ));
53 }
54 },
55 #[cfg(all(feature = "vaapi", not(feature = "nvidia")))]
57 None => VideoEncoderType::H264Vaapi,
58 #[cfg(all(feature = "nvidia", not(feature = "vaapi")))]
59 None => VideoEncoderType::H264Nvenc,
60 };
61 Ok(match encoder_type {
62 #[cfg(feature = "vaapi")]
63 VideoEncoderType::H264Vaapi => {
64 DynamicEncoder::Vaapi(VaapiEncoder::new(width, height, quality_preset)?)
65 }
66 #[cfg(feature = "nvidia")]
67 VideoEncoderType::H264Nvenc => {
68 DynamicEncoder::Nvenc(NvencEncoder::new(width, height, quality_preset)?)
69 }
70 })
71 }
72}
73
74impl VideoEncoder for DynamicEncoder {
75 type Output = EncodedVideoFrame;
76
77 fn reset(&mut self) -> Result<()> {
78 match self {
79 #[cfg(feature = "vaapi")]
80 DynamicEncoder::Vaapi(enc) => enc.reset(),
81 #[cfg(feature = "nvidia")]
82 DynamicEncoder::Nvenc(enc) => enc.reset(),
83 }
84 }
85
86 fn output(&mut self) -> Option<Receiver<Self::Output>> {
87 match self {
88 #[cfg(feature = "vaapi")]
89 DynamicEncoder::Vaapi(enc) => enc.output(),
90 #[cfg(feature = "nvidia")]
91 DynamicEncoder::Nvenc(enc) => enc.output(),
92 }
93 }
94
95 fn drop_processor(&mut self) {
96 match self {
97 #[cfg(feature = "vaapi")]
98 DynamicEncoder::Vaapi(enc) => enc.drop_processor(),
99 #[cfg(feature = "nvidia")]
100 DynamicEncoder::Nvenc(enc) => enc.drop_processor(),
101 }
102 }
103
104 fn drain(&mut self) -> Result<()> {
105 match self {
106 #[cfg(feature = "vaapi")]
107 DynamicEncoder::Vaapi(enc) => enc.drain(),
108 #[cfg(feature = "nvidia")]
109 DynamicEncoder::Nvenc(enc) => enc.drain(),
110 }
111 }
112
113 fn get_encoder(&self) -> &Option<encoder::Video> {
114 match self {
115 #[cfg(feature = "vaapi")]
116 DynamicEncoder::Vaapi(enc) => enc.get_encoder(),
117 #[cfg(feature = "nvidia")]
118 DynamicEncoder::Nvenc(enc) => enc.get_encoder(),
119 }
120 }
121}
122
123impl ProcessingThread for DynamicEncoder {
124 fn process(&mut self, frame: RawVideoFrame) -> Result<()> {
125 match self {
126 #[cfg(feature = "vaapi")]
127 DynamicEncoder::Vaapi(enc) => enc.process(frame),
128 #[cfg(feature = "nvidia")]
129 DynamicEncoder::Nvenc(enc) => enc.process(frame),
130 }
131 }
132
133 fn thread_setup(&mut self) -> Result<()> {
134 match self {
135 #[cfg(feature = "vaapi")]
136 DynamicEncoder::Vaapi(enc) => enc.thread_setup(),
137 #[cfg(feature = "nvidia")]
138 DynamicEncoder::Nvenc(enc) => enc.thread_setup(),
139 }
140 }
141
142 fn thread_teardown(&mut self) -> Result<()> {
143 match self {
144 #[cfg(feature = "vaapi")]
145 DynamicEncoder::Vaapi(enc) => enc.thread_teardown(),
146 #[cfg(feature = "nvidia")]
147 DynamicEncoder::Nvenc(enc) => enc.thread_teardown(),
148 }
149 }
150}
151
152impl PipewireSPA for DynamicEncoder {
153 #[allow(unreachable_code)]
154 fn get_spa_definition() -> Result<pipewire::spa::pod::Object> {
155 #[cfg(all(feature = "vaapi", feature = "nvidia"))]
157 return match detect_gpu_vendor()? {
158 GpuVendor::NVIDIA => NvencEncoder::get_spa_definition(),
159 GpuVendor::AMD | GpuVendor::INTEL => VaapiEncoder::get_spa_definition(),
160 GpuVendor::UNKNOWN => Err(WaycapError::Init(
161 "Unknown/Unimplemented GPU vendor".to_string(),
162 )),
163 };
164 #[cfg(all(feature = "vaapi", not(feature = "nvidia")))]
165 return VaapiEncoder::get_spa_definition();
166 #[cfg(all(feature = "nvidia", not(feature = "vaapi")))]
167 return NvencEncoder::get_spa_definition();
168 unreachable!()
169 }
170}