waycap_rs/encoders/
dynamic_encoder.rs1use crossbeam::channel::Receiver;
2use ffmpeg_next::codec::encoder;
3
4use crate::{
5 encoders::{
6 nvenc_encoder::NvencEncoder,
7 vaapi_encoder::VaapiEncoder,
8 video::{PipewireSPA, ProcessingThread},
9 },
10 types::{
11 config::VideoEncoder as VideoEncoderType,
12 error::{Result, WaycapError},
13 video_frame::{EncodedVideoFrame, RawVideoFrame},
14 },
15 waycap_egl::{EglContext, GpuVendor},
16 VideoEncoder,
17};
18
19pub enum DynamicEncoder {
20 Vaapi(VaapiEncoder),
21 Nvenc(NvencEncoder),
22}
23
24impl DynamicEncoder {
25 pub(crate) fn new(
26 encoder_type: Option<VideoEncoderType>,
27 width: u32,
28 height: u32,
29 quality_preset: crate::types::config::QualityPreset,
30 ) -> crate::types::error::Result<DynamicEncoder> {
31 let encoder_type = match encoder_type {
32 Some(typ) => typ,
33 None => {
34 let dummy_context = EglContext::new(100, 100)?;
36 match dummy_context.get_gpu_vendor() {
37 GpuVendor::NVIDIA => VideoEncoderType::H264Nvenc,
38 GpuVendor::AMD | GpuVendor::INTEL => VideoEncoderType::H264Vaapi,
39 GpuVendor::UNKNOWN => {
40 return Err(WaycapError::Init(
41 "Unknown/Unimplemented GPU vendor".to_string(),
42 ));
43 }
44 }
45 }
46 };
47 Ok(match encoder_type {
48 VideoEncoderType::H264Nvenc => {
49 DynamicEncoder::Nvenc(NvencEncoder::new(width, height, quality_preset)?)
50 }
51 VideoEncoderType::H264Vaapi => {
52 DynamicEncoder::Vaapi(VaapiEncoder::new(width, height, quality_preset)?)
53 }
54 })
55 }
56}
57
58impl VideoEncoder for DynamicEncoder {
59 type Output = EncodedVideoFrame;
60
61 fn reset(&mut self) -> Result<()> {
62 match self {
63 DynamicEncoder::Vaapi(enc) => enc.reset(),
64 DynamicEncoder::Nvenc(enc) => enc.reset(),
65 }
66 }
67
68 fn output(&mut self) -> Option<Receiver<Self::Output>> {
69 match self {
70 DynamicEncoder::Vaapi(enc) => enc.output(),
71 DynamicEncoder::Nvenc(enc) => enc.output(),
72 }
73 }
74
75 fn drop_processor(&mut self) {
76 match self {
77 DynamicEncoder::Vaapi(enc) => enc.drop_processor(),
78 DynamicEncoder::Nvenc(enc) => enc.drop_processor(),
79 }
80 }
81
82 fn drain(&mut self) -> Result<()> {
83 match self {
84 DynamicEncoder::Vaapi(enc) => enc.drain(),
85 DynamicEncoder::Nvenc(enc) => enc.drain(),
86 }
87 }
88
89 fn get_encoder(&self) -> &Option<encoder::Video> {
90 match self {
91 DynamicEncoder::Vaapi(enc) => enc.get_encoder(),
92 DynamicEncoder::Nvenc(enc) => enc.get_encoder(),
93 }
94 }
95}
96
97impl ProcessingThread for DynamicEncoder {
98 fn process(&mut self, frame: RawVideoFrame) -> Result<()> {
99 match self {
100 DynamicEncoder::Vaapi(enc) => enc.process(frame),
101 DynamicEncoder::Nvenc(enc) => enc.process(frame),
102 }
103 }
104 fn thread_setup(&mut self) -> Result<()> {
105 match self {
106 DynamicEncoder::Vaapi(enc) => enc.thread_setup(),
107 DynamicEncoder::Nvenc(enc) => enc.thread_setup(),
108 }
109 }
110
111 fn thread_teardown(&mut self) -> Result<()> {
112 match self {
113 DynamicEncoder::Vaapi(enc) => enc.thread_teardown(),
114 DynamicEncoder::Nvenc(enc) => enc.thread_teardown(),
115 }
116 }
117}
118
119impl PipewireSPA for DynamicEncoder {
120 fn get_spa_definition() -> Result<pipewire::spa::pod::Object> {
121 let dummy_context = EglContext::new(100, 100)?;
122 match dummy_context.get_gpu_vendor() {
123 GpuVendor::NVIDIA => NvencEncoder::get_spa_definition(),
124 GpuVendor::AMD | GpuVendor::INTEL => VaapiEncoder::get_spa_definition(),
125 GpuVendor::UNKNOWN => Err(WaycapError::Init(
126 "Unknown/Unimplemented GPU vendor".to_string(),
127 )),
128 }
129 }
130}