@@ -3,10 +3,7 @@ use crate::{
3
3
output_pipeline,
4
4
screen_capture:: { ScreenCaptureConfig , ScreenCaptureFormat } ,
5
5
} ;
6
- use :: windows:: {
7
- Graphics :: Capture :: GraphicsCaptureItem ,
8
- Win32 :: Graphics :: Direct3D11 :: { D3D11_BOX , ID3D11Device } ,
9
- } ;
6
+ use :: windows:: Win32 :: Graphics :: Direct3D11 :: { D3D11_BOX , ID3D11Device } ;
10
7
use anyhow:: anyhow;
11
8
use cap_fail:: fail_err;
12
9
use cap_media_info:: { AudioInfo , VideoInfo } ;
@@ -24,7 +21,7 @@ use std::{
24
21
collections:: VecDeque ,
25
22
time:: { Duration , Instant } ,
26
23
} ;
27
- use tracing:: { info, trace} ;
24
+ use tracing:: { error , info, trace} ;
28
25
29
26
const WINDOW_DURATION : Duration = Duration :: from_secs ( 3 ) ;
30
27
const LOG_INTERVAL : Duration = Duration :: from_secs ( 5 ) ;
@@ -121,18 +118,12 @@ impl ScreenCaptureConfig<Direct3DCapture> {
121
118
Some ( Duration :: from_secs_f64 ( 1.0 / self . config . fps as f64 ) ) ;
122
119
}
123
120
124
- let display = Display :: from_id ( & self . config . display )
125
- . ok_or_else ( || SourceError :: NoDisplay ( self . config . display . clone ( ) ) ) ?;
126
-
127
- let capture_item = display
128
- . raw_handle ( )
129
- . try_as_capture_item ( )
130
- . map_err ( SourceError :: AsCaptureItem ) ?;
131
-
121
+ // Store the display ID instead of GraphicsCaptureItem to avoid COM threading issues
122
+ // The GraphicsCaptureItem will be created on the capture thread
132
123
Ok ( (
133
124
VideoSourceConfig {
134
125
video_info : self . video_info ,
135
- capture_item ,
126
+ display_id : self . config . display . clone ( ) ,
136
127
settings,
137
128
d3d_device : self . d3d_device . clone ( ) ,
138
129
} ,
@@ -149,7 +140,7 @@ pub enum VideoSourceError {
149
140
150
141
pub struct VideoSourceConfig {
151
142
video_info : VideoInfo ,
152
- capture_item : GraphicsCaptureItem ,
143
+ display_id : DisplayId ,
153
144
settings : scap_direct3d:: Settings ,
154
145
pub d3d_device : ID3D11Device ,
155
146
}
@@ -170,9 +161,9 @@ impl output_pipeline::VideoSource for VideoSource {
170
161
async fn setup (
171
162
VideoSourceConfig {
172
163
video_info,
173
- capture_item ,
164
+ display_id ,
174
165
settings,
175
- d3d_device,
166
+ d3d_device, // Share the D3D device with the encoder to avoid device mismatch
176
167
} : Self :: Config ,
177
168
mut video_tx : mpsc:: Sender < Self :: Frame > ,
178
169
ctx : & mut output_pipeline:: SetupCtx ,
@@ -186,6 +177,28 @@ impl output_pipeline::VideoSource for VideoSource {
186
177
ctx. tasks ( ) . spawn_thread ( "d3d-capture-thread" , move || {
187
178
cap_mediafoundation_utils:: thread_init ( ) ;
188
179
180
+ // Look up the display and create the GraphicsCaptureItem on this thread to avoid COM threading issues
181
+ let capture_item = match Display :: from_id ( & display_id) {
182
+ Some ( display) => {
183
+ match display. raw_handle ( ) . try_as_capture_item ( ) {
184
+ Ok ( item) => {
185
+ trace ! ( "GraphicsCaptureItem created successfully on capture thread" ) ;
186
+ item
187
+ }
188
+ Err ( e) => {
189
+ error ! ( "Failed to create GraphicsCaptureItem on capture thread: {}" , e) ;
190
+ let _ = error_tx. send ( anyhow ! ( "Failed to create GraphicsCaptureItem: {}" , e) ) ;
191
+ return ;
192
+ }
193
+ }
194
+ }
195
+ None => {
196
+ error ! ( "Display not found for ID: {:?}" , display_id) ;
197
+ let _ = error_tx. send ( anyhow ! ( "Display not found for ID: {:?}" , display_id) ) ;
198
+ return ;
199
+ }
200
+ } ;
201
+
189
202
let res = scap_direct3d:: Capturer :: new (
190
203
capture_item,
191
204
settings,
@@ -206,26 +219,39 @@ impl output_pipeline::VideoSource for VideoSource {
206
219
Ok ( ( ) )
207
220
}
208
221
} ,
209
- Some ( d3d_device) ,
222
+ Some ( d3d_device) , // Use the same D3D device as the encoder
210
223
) ;
211
224
212
225
let mut capturer = match res {
213
- Ok ( capturer) => capturer,
226
+ Ok ( capturer) => {
227
+ trace ! ( "D3D capturer created successfully" ) ;
228
+ capturer
229
+ }
214
230
Err ( e) => {
231
+ error ! ( "Failed to create D3D capturer: {}" , e) ;
215
232
let _ = error_tx. send ( e. into ( ) ) ;
216
233
return ;
217
234
}
218
235
} ;
219
236
220
237
let Ok ( VideoControl :: Start ( reply) ) = ctrl_rx. recv ( ) else {
238
+ error ! ( "Failed to receive Start control message - channel disconnected" ) ;
239
+ let _ = error_tx. send ( anyhow ! ( "Control channel disconnected before Start" ) ) ;
221
240
return ;
222
241
} ;
223
242
224
- if reply. send ( capturer. start ( ) . map_err ( Into :: into) ) . is_err ( ) {
243
+ trace ! ( "Starting D3D capturer" ) ;
244
+ let start_result = capturer. start ( ) . map_err ( Into :: into) ;
245
+ if let Err ( ref e) = start_result {
246
+ error ! ( "Failed to start D3D capturer: {}" , e) ;
247
+ }
248
+ if reply. send ( start_result) . is_err ( ) {
249
+ error ! ( "Failed to send start result - receiver dropped" ) ;
225
250
return ;
226
251
}
227
252
228
253
let Ok ( VideoControl :: Stop ( reply) ) = ctrl_rx. recv ( ) else {
254
+ trace ! ( "Failed to receive Stop control message - channel disconnected (expected during shutdown)" ) ;
229
255
return ;
230
256
} ;
231
257
0 commit comments