waycap_rs/encoders/
rgba_image_encoder.rs1use crate::{
2 encoders::video::{PipewireSPA, ProcessingThread},
3 types::video_frame::RawVideoFrame,
4 VideoEncoder,
5};
6use crossbeam::channel::{Receiver, Sender};
7
8use crate::types::error::Result;
9use pipewire as pw;
10
11pub struct RgbaImageEncoder {
17 image_sender: Sender<image::RgbaImage>,
18 image_receiver: Receiver<image::RgbaImage>,
19}
20
21impl Default for RgbaImageEncoder {
22 fn default() -> Self {
23 let (image_sender, image_receiver) = crossbeam::channel::bounded(10);
24 Self {
25 image_sender,
26 image_receiver,
27 }
28 }
29}
30
31impl ProcessingThread for RgbaImageEncoder {
32 fn process(&mut self, frame: RawVideoFrame) -> Result<()> {
33 let mut raw = frame.data.clone();
34 bgra_to_rgba_inplace(&mut raw);
35 let image =
36 image::RgbaImage::from_raw(frame.dimensions.width, frame.dimensions.height, raw)
37 .unwrap();
38 match self.image_sender.try_send(image) {
39 Ok(_) => {}
40 Err(crossbeam::channel::TrySendError::Full(_)) => {
41 log::error!("Could not send encoded video frame. Receiver is full");
42 }
43 Err(crossbeam::channel::TrySendError::Disconnected(_)) => {
44 log::error!("Could not send encoded video frame. Receiver disconnected");
45 }
46 }
47 Ok(())
48 }
49}
50
51impl VideoEncoder for RgbaImageEncoder {
52 type Output = image::RgbaImage;
53
54 fn reset(&mut self) -> crate::types::error::Result<()> {
55 Ok(())
56 }
57
58 fn output(&mut self) -> Option<crossbeam::channel::Receiver<Self::Output>> {
59 Some(self.image_receiver.clone())
60 }
61
62 fn drop_processor(&mut self) {}
63
64 fn drain(&mut self) -> crate::types::error::Result<()> {
65 Ok(())
66 }
67
68 fn get_encoder(&self) -> &Option<ffmpeg_next::codec::encoder::Video> {
69 &None
70 }
71}
72
73impl PipewireSPA for RgbaImageEncoder {
74 fn get_spa_definition() -> Result<pipewire::spa::pod::Object> {
75 Ok(pw::spa::pod::object!(
76 pw::spa::utils::SpaTypes::ObjectParamFormat,
77 pw::spa::param::ParamType::EnumFormat,
78 pw::spa::pod::property!(
79 pw::spa::param::format::FormatProperties::MediaType,
80 Id,
81 pw::spa::param::format::MediaType::Video
82 ),
83 pw::spa::pod::property!(
84 pw::spa::param::format::FormatProperties::MediaSubtype,
85 Id,
86 pw::spa::param::format::MediaSubtype::Raw
87 ),
88 pw::spa::pod::property!(
89 pw::spa::param::format::FormatProperties::VideoFormat,
90 Id,
91 pw::spa::param::video::VideoFormat::BGRA
92 ),
93 pw::spa::pod::property!(
94 pw::spa::param::format::FormatProperties::VideoSize,
95 Choice,
96 Range,
97 Rectangle,
98 pw::spa::utils::Rectangle {
99 width: 2560,
100 height: 1440
101 }, pw::spa::utils::Rectangle {
103 width: 1,
104 height: 1
105 }, pw::spa::utils::Rectangle {
107 width: 4096,
108 height: 4096
109 } ),
111 pw::spa::pod::property!(
112 pw::spa::param::format::FormatProperties::VideoFramerate,
113 Choice,
114 Range,
115 Fraction,
116 pw::spa::utils::Fraction { num: 240, denom: 1 }, pw::spa::utils::Fraction { num: 0, denom: 1 }, pw::spa::utils::Fraction { num: 244, denom: 1 } ),
120 ))
121 }
122}
123
124pub fn bgra_to_rgba_inplace(buf: &mut [u8]) {
129 let (chunked, _) = buf.as_chunks_mut::<4>();
131
132 for p in chunked {
133 let bgra = u32::from_be_bytes(*p);
134 let argb = bgra.swap_bytes();
135 let rgba = argb.rotate_left(8);
136 *p = rgba.to_be_bytes();
137 }
138}