11use crate :: wayland:: {
2- CapturedDmaBuffer , CapturedDmaBufferSync , CapturedFrame , CapturedFrameBuffer ,
3- CapturedFrameFormat , PipewireOptions , PixelFormat , RgbaSwizzle ,
2+ CapturedDmaBuffer , CapturedDmaBufferSync , CapturedDmaRegion , CapturedFrame ,
3+ CapturedFrameBuffer , CapturedFrameFormat , PipewireOptions , PixelFormat , RgbaSwizzle ,
44} ;
55use pipewire:: {
66 context:: ContextRc ,
@@ -23,9 +23,11 @@ use pipewire::{
2323} ;
2424use smallvec:: SmallVec ;
2525use 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} ;
3133use tokio:: sync:: oneshot;
@@ -44,12 +46,52 @@ impl Drop for BufferGuard<'_> {
4446struct 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
5255impl 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
476508pub ( 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+
529581fn 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+
778859fn 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