Skip to content

Commit 254114a

Browse files
committed
misc fixes
1 parent 41a42e6 commit 254114a

6 files changed

Lines changed: 170 additions & 58 deletions

File tree

media-video/capture/src/wayland/mod.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ pub struct CapturedFrame {
118118
pub buffer: CapturedFrameBuffer,
119119
}
120120

121-
/// Defines the layout of the data inside a [`CapturedFrameBuffer`]
121+
/// Defines the data layout inside a [`CapturedFrameBuffer`]
122122
#[derive(Debug)]
123123
pub enum CapturedFrameFormat {
124124
NV12 {
@@ -155,9 +155,18 @@ impl std::fmt::Debug for CapturedFrameBuffer {
155155
pub struct CapturedDmaBuffer {
156156
pub fd: OwnedFd,
157157
pub modifier: u64,
158+
pub region: Option<CapturedDmaRegion>,
158159
pub sync: Option<CapturedDmaBufferSync>,
159160
}
160161

162+
#[derive(Debug, Clone, Copy)]
163+
pub struct CapturedDmaRegion {
164+
pub x: i32,
165+
pub y: i32,
166+
pub width: u32,
167+
pub height: u32,
168+
}
169+
161170
#[derive(Debug)]
162171
pub struct CapturedDmaBufferSync {
163172
pub acquire_point: u64,
@@ -171,24 +180,34 @@ pub struct CapturedDmaBufferSync {
171180
#[error("Stream has been closed")]
172181
pub struct StreamClosedError;
173182

183+
/// Handle to a current capture stream
184+
///
185+
/// Dropping it does **not** end the stream.
186+
///
187+
/// To properly close a capture stream call [`StreamHandle::close`].
174188
pub struct StreamHandle {
175189
session: Session<'static, Screencast<'static>>,
176190
sender: pipewire::channel::Sender<stream::Command>,
177191
}
178192

179193
impl StreamHandle {
194+
/// Continue playing the stream.
195+
///
196+
/// Should only be called after pausing the stream - created captures are automatically playing
180197
pub fn play(&self) -> Result<(), StreamClosedError> {
181198
self.sender
182199
.send(stream::Command::Play)
183200
.map_err(|_| StreamClosedError)
184201
}
185202

203+
/// Pause the stream, can be unpaused using [`StreamHandle::play`].
186204
pub fn pause(&self) -> Result<(), StreamClosedError> {
187205
self.sender
188206
.send(stream::Command::Pause)
189207
.map_err(|_| StreamClosedError)
190208
}
191209

210+
/// Gracefully close the pipewire stream and close the dbus connection.
192211
pub async fn close(&self) -> Result<(), StreamClosedError> {
193212
if let Err(e) = self.session.close().await {
194213
log::warn!("Failed to close xdg session properly {e}");
@@ -198,6 +217,15 @@ impl StreamHandle {
198217
.send(stream::Command::Close)
199218
.map_err(|_| StreamClosedError)
200219
}
220+
221+
/// Renegotiate the stream without the given DRM modifier
222+
///
223+
/// All future renegotiations will not include this modifier.
224+
pub fn remove_modifier(&self, modifier: u64) -> Result<(), StreamClosedError> {
225+
self.sender
226+
.send(stream::Command::RemoveModifier(modifier))
227+
.map_err(|_| StreamClosedError)
228+
}
201229
}
202230

203231
#[derive(Debug, thiserror::Error)]

media-video/capture/src/wayland/stream.rs

Lines changed: 128 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::wayland::{
2-
CapturedDmaBuffer, CapturedDmaBufferSync, CapturedFrame, CapturedFrameBuffer,
3-
CapturedFrameFormat, PipewireOptions, PixelFormat, RgbaSwizzle,
2+
CapturedDmaBuffer, CapturedDmaBufferSync, CapturedDmaRegion, CapturedFrame,
3+
CapturedFrameBuffer, CapturedFrameFormat, PipewireOptions, PixelFormat, RgbaSwizzle,
44
};
55
use pipewire::{
66
context::ContextRc,
@@ -23,9 +23,11 @@ use pipewire::{
2323
};
2424
use smallvec::SmallVec;
2525
use std::{
26+
cell::RefCell,
2627
io::Cursor,
2728
os::fd::{BorrowedFd, OwnedFd, RawFd},
2829
ptr::{null, null_mut},
30+
rc::Rc,
2931
slice::from_raw_parts,
3032
};
3133
use tokio::sync::oneshot;
@@ -44,12 +46,52 @@ impl Drop for BufferGuard<'_> {
4446
struct UserStreamState {
4547
main_loop: MainLoopWeak,
4648
options: PipewireOptions,
49+
has_video_modifier: bool,
4750

4851
format: VideoInfoRaw,
4952
on_frame: Box<dyn FnMut(CapturedFrame) -> bool + Send>,
5053
}
5154

5255
impl UserStreamState {
56+
fn update_params(&mut self, stream: &Stream) {
57+
if let Some(dma_options) = &self.options.dma_usage
58+
&& self.has_video_modifier
59+
{
60+
let dma_buffer_params = serialize_object(dma_buffer_params(
61+
dma_options.num_buffers as i32,
62+
dma_options.request_sync_obj,
63+
));
64+
let sync_obj_params = serialize_object(sync_obj_params());
65+
let crop_region_params = serialize_object(crop_region_param());
66+
67+
let mut update_params: SmallVec<[&Pod; 2]> = smallvec::SmallVec::new();
68+
69+
update_params
70+
.push(Pod::from_bytes(&dma_buffer_params).expect("object is serialized as pod"));
71+
72+
if dma_options.request_sync_obj {
73+
update_params
74+
.push(Pod::from_bytes(&sync_obj_params).expect("object is serialized as pod"));
75+
}
76+
77+
update_params
78+
.push(Pod::from_bytes(&crop_region_params).expect("object is serialized as pod"));
79+
80+
if let Err(e) = stream.update_params(&mut update_params) {
81+
log::error!("Failed to update stream params: {e}");
82+
}
83+
} else {
84+
let mem_buffer_params = serialize_object(mem_buffer_params());
85+
86+
let mut update_params =
87+
[Pod::from_bytes(&mem_buffer_params).expect("object is serialized as pod")];
88+
89+
if let Err(e) = stream.update_params(&mut update_params) {
90+
log::error!("Failed to update stream params: {e}");
91+
}
92+
}
93+
}
94+
5395
fn handle_state_changed(&mut self, _stream: &Stream, old: StreamState, new: StreamState) {
5496
log::debug!("stream changed: {old:?} -> {new:?}");
5597

@@ -96,7 +138,7 @@ impl UserStreamState {
96138
);
97139

98140
// Check explicitly if the Video modifier property has been set
99-
let video_modifier_is_set = unsafe {
141+
self.has_video_modifier = unsafe {
100142
let prop = spa::sys::spa_pod_find_prop(
101143
param.as_raw_ptr(),
102144
null(),
@@ -106,38 +148,7 @@ impl UserStreamState {
106148
!prop.is_null()
107149
};
108150

109-
if let Some(dma_options) = &self.options.dma_usage
110-
&& video_modifier_is_set
111-
{
112-
let dma_buffer_params = serialize_object(dma_buffer_params(
113-
dma_options.num_buffers as i32,
114-
dma_options.request_sync_obj,
115-
));
116-
let sync_obj_params = serialize_object(sync_obj_params());
117-
118-
let mut update_params: SmallVec<[&Pod; 2]> = smallvec::SmallVec::new();
119-
120-
update_params
121-
.push(Pod::from_bytes(&dma_buffer_params).expect("object is serialized as pod"));
122-
123-
if dma_options.request_sync_obj {
124-
update_params
125-
.push(Pod::from_bytes(&sync_obj_params).expect("object is serialized as pod"));
126-
}
127-
128-
if let Err(e) = stream.update_params(&mut update_params) {
129-
log::error!("Failed to update stream params: {e}");
130-
}
131-
} else {
132-
let mem_buffer_params = serialize_object(mem_buffer_params());
133-
134-
let mut update_params =
135-
[Pod::from_bytes(&mem_buffer_params).expect("object is serialized as pod")];
136-
137-
if let Err(e) = stream.update_params(&mut update_params) {
138-
log::error!("Failed to update stream params: {e}");
139-
}
140-
}
151+
self.update_params(stream);
141152
}
142153

143154
fn handle_process(&mut self, stream: &Stream) {
@@ -293,6 +304,25 @@ impl UserStreamState {
293304
_ => unreachable!(),
294305
};
295306

307+
let region = metas.iter().find_map(|meta| {
308+
if meta.type_ == spa::sys::SPA_META_VideoCrop {
309+
let meta = unsafe {
310+
meta.data
311+
.cast::<spa::sys::spa_meta_region>()
312+
.read_unaligned()
313+
};
314+
315+
Some(CapturedDmaRegion {
316+
x: meta.region.position.x,
317+
y: meta.region.position.y,
318+
width: meta.region.size.width,
319+
height: meta.region.size.height,
320+
})
321+
} else {
322+
None
323+
}
324+
});
325+
296326
let sync_timeline = metas
297327
.iter()
298328
.find(|m| m.type_ == spa::sys::SPA_META_SyncTimeline);
@@ -330,6 +360,7 @@ impl UserStreamState {
330360
buffer: CapturedFrameBuffer::DmaBuf(CapturedDmaBuffer {
331361
fd: clone_fd(dma_data[0].fd as RawFd),
332362
modifier: self.format.modifier(),
363+
region,
333364
sync,
334365
}),
335366
}
@@ -471,6 +502,7 @@ pub(super) enum Command {
471502
Play,
472503
Pause,
473504
Close,
505+
RemoveModifier(u64),
474506
}
475507

476508
pub(super) fn start(
@@ -493,7 +525,7 @@ pub(super) fn start(
493525

494526
let (tx, rx) = pipewire::channel::channel();
495527

496-
let (stream, _listener) = match build_stream(&mainloop, node_id, fd, options, role, on_frame) {
528+
let data = match build_stream(&mainloop, node_id, fd, options, role, on_frame) {
497529
Ok(data_to_not_drop) => data_to_not_drop,
498530
Err(e) => {
499531
let _ = result_tx.send(Err(e));
@@ -503,20 +535,32 @@ pub(super) fn start(
503535

504536
let _attach_guard = rx.attach(mainloop.loop_(), move |command| match command {
505537
Command::Play => {
506-
if let Err(e) = stream.set_active(true) {
538+
if let Err(e) = data.stream.set_active(true) {
507539
log::warn!("Failed to handle Play command: {e}");
508540
}
509541
}
510542
Command::Pause => {
511-
if let Err(e) = stream.set_active(false) {
543+
if let Err(e) = data.stream.set_active(false) {
512544
log::warn!("Failed to handle Pause command: {e}");
513545
}
514546
}
515547
Command::Close => {
516-
if let Err(e) = stream.disconnect() {
548+
if let Err(e) = data.stream.disconnect() {
517549
log::warn!("Failed to handle Close command: {e}");
518550
}
519551
}
552+
Command::RemoveModifier(modifier) => {
553+
let mut user_data = data.user_data.borrow_mut();
554+
555+
if let Some(dma_usage) = &mut user_data.options.dma_usage {
556+
let prev_modifier_len = dma_usage.supported_modifier.len();
557+
dma_usage.supported_modifier.retain(|m| *m != modifier);
558+
559+
if prev_modifier_len != dma_usage.supported_modifier.len() {
560+
user_data.update_params(&data.stream);
561+
}
562+
}
563+
}
520564
});
521565

522566
if result_tx.send(Ok(tx)).is_err() {
@@ -526,22 +570,31 @@ pub(super) fn start(
526570
mainloop.run();
527571
}
528572

573+
struct StreamData {
574+
stream: StreamRc,
575+
// This is just a guard object needed to keep alive
576+
#[expect(dead_code)]
577+
listener: StreamListener<Rc<RefCell<UserStreamState>>>,
578+
user_data: Rc<RefCell<UserStreamState>>,
579+
}
580+
529581
fn build_stream(
530582
mainloop: &MainLoopRc,
531583
node_id: Option<u32>,
532584
fd: OwnedFd,
533585
options: PipewireOptions,
534586
role: &'static str,
535587
on_frame: Box<dyn FnMut(CapturedFrame) -> bool + Send>,
536-
) -> Result<(StreamRc, StreamListener<UserStreamState>), pipewire::Error> {
588+
) -> Result<StreamData, pipewire::Error> {
537589
let context = ContextRc::new(mainloop, None)?;
538590
let core = context.connect_fd_rc(fd, None)?;
539-
let data = UserStreamState {
591+
let user_data = Rc::new(RefCell::new(UserStreamState {
540592
format: Default::default(),
541593
main_loop: mainloop.downgrade(),
542594
on_frame,
543595
options: options.clone(),
544-
};
596+
has_video_modifier: false,
597+
}));
545598

546599
let stream = StreamRc::new(
547600
core,
@@ -554,15 +607,19 @@ fn build_stream(
554607
)?;
555608

556609
let listener = stream
557-
.add_local_listener_with_user_data(data)
610+
.add_local_listener_with_user_data(user_data.clone())
558611
.state_changed(|stream, user_data, old, new| {
559-
user_data.handle_state_changed(stream, old, new);
612+
user_data
613+
.borrow_mut()
614+
.handle_state_changed(stream, old, new);
560615
})
561616
.param_changed(|stream, user_data, id, param| {
562-
user_data.handle_param_changed(stream, id, param);
617+
user_data
618+
.borrow_mut()
619+
.handle_param_changed(stream, id, param);
563620
})
564621
.process(move |stream, user_data| {
565-
user_data.handle_process(stream);
622+
user_data.borrow_mut().handle_process(stream);
566623
})
567624
.register()?;
568625

@@ -595,7 +652,11 @@ fn build_stream(
595652
&mut connect_params,
596653
)?;
597654

598-
Ok((stream, listener))
655+
Ok(StreamData {
656+
stream,
657+
listener,
658+
user_data,
659+
})
599660
}
600661

601662
/// Build the video format capabilities which will be used to negotiate a video stream with pipewire
@@ -775,6 +836,26 @@ fn sync_obj_params() -> Object {
775836
}
776837
}
777838

839+
fn crop_region_param() -> Object {
840+
Object {
841+
type_: spa::sys::SPA_TYPE_OBJECT_ParamMeta,
842+
id: spa::sys::SPA_PARAM_Meta,
843+
properties: [
844+
Property {
845+
key: spa::sys::SPA_PARAM_META_type,
846+
flags: PropertyFlags::empty(),
847+
value: Value::Id(Id(spa::sys::SPA_META_VideoCrop)),
848+
},
849+
Property {
850+
key: spa::sys::SPA_PARAM_META_size,
851+
flags: PropertyFlags::empty(),
852+
value: Value::Int(size_of::<spa::sys::spa_meta_region>() as i32),
853+
},
854+
]
855+
.into(),
856+
}
857+
}
858+
778859
fn serialize_object(object: Object) -> Vec<u8> {
779860
PodSerializer::serialize(Cursor::new(Vec::new()), &Value::Object(object))
780861
.expect("objects must be serializable")

0 commit comments

Comments
 (0)