1- use std:: {
2- collections:: HashMap ,
3- sync:: {
4- mpsc:: { sync_channel, Receiver , SyncSender , TryRecvError , TrySendError } ,
5- RwLock ,
6- } ,
7- } ;
1+ use std:: sync:: mpsc:: { sync_channel, Receiver , TryRecvError , TrySendError } ;
82
9- use lazy_static:: lazy_static;
103use windows:: {
114 core:: { IInspectable , Interface , Result } ,
125 Foundation :: TypedEventHandler ,
@@ -15,62 +8,18 @@ use windows::{
158 DirectX :: { Direct3D11 :: IDirect3DDevice , DirectXPixelFormat } ,
169 SizeInt32 ,
1710 } ,
18- Win32 :: {
19- Foundation :: HWND ,
20- Graphics :: Direct3D11 :: {
21- ID3D11Device , ID3D11DeviceContext , ID3D11Texture2D , D3D11_BOX ,
22- D3D11_MAPPED_SUBRESOURCE , D3D11_TEXTURE2D_DESC ,
23- } ,
24- UI :: {
25- Accessibility :: { SetWinEventHook , UnhookWinEvent , HWINEVENTHOOK } ,
26- WindowsAndMessaging :: { EVENT_OBJECT_DESTROY , WINEVENT_OUTOFCONTEXT } ,
27- } ,
11+ Win32 :: Graphics :: Direct3D11 :: {
12+ ID3D11Device , ID3D11DeviceContext , ID3D11Texture2D , D3D11_BOX , D3D11_MAPPED_SUBRESOURCE ,
13+ D3D11_TEXTURE2D_DESC ,
2814 } ,
2915} ;
3016
3117use crate :: {
3218 staging_texture:: StagingTexture ,
3319 util:: { create_d3d_device, create_direct3d_device, get_dxgi_interface_from_object} ,
34- window :: Window ,
20+ Capturable ,
3521} ;
3622
37- lazy_static ! {
38- static ref OBJECT_DESTROYED_USER_DATA : RwLock <HashMap <isize , ( isize , SyncSender <( ) >) >> =
39- Default :: default ( ) ;
40- }
41-
42- extern "system" fn object_destroyed_cb (
43- this : HWINEVENTHOOK ,
44- _: u32 ,
45- handle : HWND ,
46- id_object : i32 ,
47- id_child : i32 ,
48- _: u32 ,
49- _: u32 ,
50- ) {
51- if id_object == 0 && id_child == 0 && handle != HWND :: default ( ) {
52- let has_been_closed = if let Ok ( handles) = OBJECT_DESTROYED_USER_DATA . read ( ) {
53- if let Some ( ( window_handle, tx) ) = handles. get ( & this. 0 ) {
54- if * window_handle == handle. 0 {
55- tx. send ( ( ) ) . ok ( ) ;
56- true
57- } else {
58- false
59- }
60- } else {
61- false
62- }
63- } else {
64- // TODO is that correct?
65- true
66- } ;
67-
68- if has_been_closed {
69- unsafe { UnhookWinEvent ( this) } ;
70- }
71- }
72- }
73-
7423pub struct Frame < ' a > {
7524 pub texture : & ' a StagingTexture ,
7625 pub ptr : D3D11_MAPPED_SUBRESOURCE ,
@@ -80,9 +29,9 @@ pub struct Capture {
8029 device : ID3D11Device ,
8130 direct3d_device : IDirect3DDevice ,
8231 context : ID3D11DeviceContext ,
83- window : Window ,
84- window_box : D3D11_BOX ,
85- window_closed_signal : Receiver < ( ) > ,
32+ capturable : Box < dyn Capturable > ,
33+ capture_box : D3D11_BOX ,
34+ capture_done_signal : Receiver < ( ) > ,
8635 frame_pool : Direct3D11CaptureFramePool ,
8736 frame_source : Receiver < Option < Direct3D11CaptureFrame > > ,
8837 session : GraphicsCaptureSession ,
@@ -92,51 +41,31 @@ pub struct Capture {
9241}
9342
9443impl Capture {
95- /// Create a new capture of `window` . This will initialize D3D11 devices, context, and Windows.Graphics.Capture's
44+ /// Create a new capture. This will initialize D3D11 devices, context, and Windows.Graphics.Capture's
9645 /// frame pool / capture session.
9746 ///
9847 /// Note that this will not start capturing yet. Call `start()` to actually start receiving frames.
99- pub fn new ( window : Window ) -> Result < Self > {
100- let d3d_device = create_d3d_device ( ) ?;
101- let d3d_context = {
48+ pub fn new ( capturable : Box < dyn Capturable > , capture_cursor : bool ) -> Result < Self > {
49+ let device = create_d3d_device ( ) ?;
50+ let context = unsafe {
10251 let mut d3d_context = None ;
103- unsafe { d3d_device . GetImmediateContext ( & mut d3d_context) } ;
52+ device . GetImmediateContext ( & mut d3d_context) ;
10453 d3d_context. expect ( "failed to create d3d_context" )
10554 } ;
106- let device = create_direct3d_device ( & d3d_device ) ?;
55+ let direct3d_device = create_direct3d_device ( & device ) ?;
10756
108- let capture_item = window . create_capture_item ( ) ?;
57+ let capture_item = capturable . create_capture_item ( ) ?;
10958 let capture_item_size = capture_item. Size ( ) ?;
11059
11160 let frame_pool = Direct3D11CaptureFramePool :: CreateFreeThreaded (
112- & device ,
61+ & direct3d_device ,
11362 DirectXPixelFormat :: B8G8R8A8UIntNormalized ,
11463 1 ,
11564 capture_item_size,
11665 ) ?;
11766
11867 let session = frame_pool. CreateCaptureSession ( & capture_item) ?;
119- session. SetIsCursorCaptureEnabled ( false ) ?;
120-
121- let ( sender, window_closed_signal) = sync_channel ( 1 ) ;
122- let hook_id = unsafe {
123- SetWinEventHook (
124- EVENT_OBJECT_DESTROY ,
125- EVENT_OBJECT_DESTROY ,
126- None ,
127- Some ( object_destroyed_cb) ,
128- // TODO filtering by process id does not always catch the moment when the window is closed
129- // why? aren't windows bound to their process ids?
130- // moreover, for explorer windows even that does not work.
131- // need some more realiable and simpler way to track window closing
132- 0 ,
133- 0 ,
134- WINEVENT_OUTOFCONTEXT ,
135- )
136- } ;
137- if let Ok ( mut handles) = OBJECT_DESTROYED_USER_DATA . write ( ) {
138- handles. insert ( hook_id. 0 , ( window. handle . 0 , sender) ) ;
139- }
68+ session. SetIsCursorCaptureEnabled ( capture_cursor) ?;
14069
14170 let ( sender, receiver) = sync_channel ( 1 << 5 ) ;
14271 frame_pool. FrameArrived (
@@ -160,15 +89,16 @@ impl Capture {
16089 ) ,
16190 ) ?;
16291
163- let window_box = window. get_client_box ( ) ;
92+ let capture_box = capturable. get_client_box ( ) ?;
93+ let capture_done_signal = capturable. get_close_notification_channel ( ) ;
16494
16595 Ok ( Self {
166- device : d3d_device ,
167- direct3d_device : device ,
168- context : d3d_context ,
169- window ,
170- window_box ,
171- window_closed_signal ,
96+ device,
97+ direct3d_device,
98+ context,
99+ capturable ,
100+ capture_box ,
101+ capture_done_signal ,
172102 frame_pool,
173103 frame_source : receiver,
174104 session,
@@ -178,9 +108,9 @@ impl Capture {
178108 } )
179109 }
180110
181- /// Get attached window .
182- pub fn window ( & self ) -> & Window {
183- & self . window
111+ /// Get attached capturable .
112+ pub fn capturable ( & self ) -> & Box < dyn Capturable > {
113+ & self . capturable
184114 }
185115
186116 /// Start capturing frames.
@@ -195,7 +125,7 @@ impl Capture {
195125 ///
196126 /// Returns:
197127 /// * `Ok(Some(...))` if there is a frame and it's been successfully captured;
198- /// * `Ok(None)` if no frames can be received from the application (i.e . when the window was closed).
128+ /// * `Ok(None)` if no frames can be received (e.g . when the window was closed).
199129 /// * `Err(...)` if an error has occured while capturing a frame.
200130 pub fn grab ( & mut self ) -> Result < Option < Frame > > {
201131 if self . grab_next ( ) ? {
@@ -223,9 +153,9 @@ impl Capture {
223153 }
224154
225155 fn recreate_frame_pool ( & mut self ) -> Result < ( ) > {
226- let capture_item = self . window . create_capture_item ( ) ?;
156+ let capture_item = self . capturable . create_capture_item ( ) ?;
227157 let capture_item_size = capture_item. Size ( ) ?;
228- self . window_box = self . window . get_client_box ( ) ;
158+ self . capture_box = self . capturable . get_client_box ( ) ? ;
229159 self . frame_pool . Recreate (
230160 & self . direct3d_device ,
231161 DirectXPixelFormat :: B8G8R8A8UIntNormalized ,
@@ -245,7 +175,7 @@ impl Capture {
245175 Err ( TryRecvError :: Empty ) => {
246176 // TODO busy loop? so uncivilized
247177 if let Ok ( ( ) ) | Err ( TryRecvError :: Disconnected ) =
248- self . window_closed_signal . try_recv ( )
178+ self . capture_done_signal . try_recv ( )
249179 {
250180 self . stop ( ) ?;
251181 return Ok ( false ) ;
@@ -267,8 +197,8 @@ impl Capture {
267197 self . recreate_frame_pool ( ) ?;
268198 let new_staging_texture = StagingTexture :: new (
269199 & self . device ,
270- self . window_box . right - self . window_box . left ,
271- self . window_box . bottom - self . window_box . top ,
200+ self . capture_box . right - self . capture_box . left ,
201+ self . capture_box . bottom - self . capture_box . top ,
272202 desc. Format ,
273203 ) ?;
274204 self . staging_texture = Some ( new_staging_texture) ;
@@ -286,7 +216,7 @@ impl Capture {
286216 0 ,
287217 Some ( & copy_src) ,
288218 0 ,
289- Some ( & self . window_box as * const _ ) ,
219+ Some ( & self . capture_box as * const _ ) ,
290220 ) ;
291221 }
292222
0 commit comments