9
9
10
10
using FlashCap . Internal ;
11
11
using System ;
12
+ using System . Diagnostics ;
12
13
using System . Runtime . CompilerServices ;
13
14
using System . Runtime . InteropServices ;
14
15
using System . Threading ;
15
16
using System . Threading . Tasks ;
17
+
16
18
using static FlashCap . Internal . NativeMethods_V4L2 ;
17
19
using static FlashCap . Internal . V4L2 . NativeMethods_V4L2_Interop ;
18
20
@@ -23,16 +25,18 @@ public sealed class V4L2Device : CaptureDevice
23
25
private const int BufferCount = 2 ;
24
26
25
27
private readonly TimestampCounter counter = new ( ) ;
28
+
26
29
private string devicePath ;
27
30
private bool transcodeIfYUV ;
28
31
private FrameProcessor frameProcessor ;
29
32
30
33
private long frameIndex ;
31
34
35
+ private readonly IntPtr [ ] pBuffers = new IntPtr [ BufferCount ] ;
36
+ private readonly int [ ] bufferLength = new int [ BufferCount ] ;
37
+
32
38
private int fd ;
33
39
private IntPtr pBih ;
34
- private IntPtr [ ] pBuffers = new IntPtr [ BufferCount ] ;
35
- private int [ ] bufferLength = new int [ BufferCount ] ;
36
40
private Thread thread ;
37
41
private int abortrfd ;
38
42
private int abortwfd ;
@@ -139,8 +143,8 @@ protected override unsafe Task OnInitializeAsync(
139
143
$ "FlashCap: Couldn't map video buffer: Code={ code } , DevicePath={ this . devicePath } ") ;
140
144
}
141
145
142
- pBuffers [ index ] = pBuffer ;
143
- bufferLength [ index ] = ( int ) buffer . length ;
146
+ this . pBuffers [ index ] = pBuffer ;
147
+ this . bufferLength [ index ] = ( int ) buffer . length ;
144
148
145
149
if ( ioctl ( fd , Interop . VIDIOC_QBUF , buffer ) < 0 )
146
150
{
@@ -188,6 +192,17 @@ protected override unsafe Task OnInitializeAsync(
188
192
}
189
193
catch
190
194
{
195
+ for ( var index = 0 ; index < pBuffers . Length ; index ++ )
196
+ {
197
+ if ( this . pBuffers [ index ] != default &&
198
+ this . bufferLength [ index ] != default )
199
+ {
200
+ munmap ( this . pBuffers [ index ] , ( ulong ) this . bufferLength [ index ] ) ;
201
+ this . pBuffers [ index ] = default ;
202
+ this . bufferLength [ index ] = default ;
203
+ }
204
+ }
205
+
191
206
close ( fd ) ;
192
207
throw ;
193
208
}
@@ -210,9 +225,9 @@ protected override Task DisposeAsync(
210
225
}
211
226
212
227
write ( this . abortwfd , new byte [ ] { 0x01 } , 1 ) ;
228
+ close ( this . abortwfd ) ;
213
229
214
230
this . thread . Join ( ) ; // TODO: awaiting
215
- close ( this . abortwfd ) ;
216
231
this . abortwfd = - 1 ;
217
232
}
218
233
}
@@ -244,12 +259,12 @@ static bool IsIgnore(int code) =>
244
259
new pollfd
245
260
{
246
261
fd = this . abortrfd ,
247
- events = POLLBITS . POLLIN ,
262
+ events = POLLBITS . POLLIN | POLLBITS . POLLHUP | POLLBITS . POLLRDHUP | POLLBITS . POLLERR ,
248
263
} ,
249
264
new pollfd
250
265
{
251
266
fd = this . fd ,
252
- events = POLLBITS . POLLIN ,
267
+ events = POLLBITS . POLLIN | POLLBITS . POLLHUP | POLLBITS . POLLRDHUP | POLLBITS . POLLERR ,
253
268
}
254
269
} ;
255
270
var buffer = Interop . Create_v4l2_buffer ( ) ;
@@ -260,12 +275,8 @@ static bool IsIgnore(int code) =>
260
275
{
261
276
while ( true )
262
277
{
263
- var result = poll ( fds , fds . Length , - 1 ) ;
264
- if ( result == 0 )
265
- {
266
- break ;
267
- }
268
- if ( result != 1 )
278
+ var pr = poll ( fds , fds . Length , - 1 ) ;
279
+ if ( pr < 0 )
269
280
{
270
281
var code = Marshal . GetLastWin32Error ( ) ;
271
282
if ( code == EINTR )
@@ -280,43 +291,79 @@ static bool IsIgnore(int code) =>
280
291
throw new ArgumentException (
281
292
$ "FlashCap: Couldn't get fd status: Code={ code } , DevicePath={ this . devicePath } ") ;
282
293
}
283
-
284
- if ( ioctl ( this . fd , Interop . VIDIOC_DQBUF , buffer ) < 0 )
294
+ if ( pr >= 1 )
285
295
{
286
- // Couldn't get, maybe discarding.
287
- if ( Marshal . GetLastWin32Error ( ) is { } code && IsIgnore ( code ) )
296
+ if ( ( fds [ 0 ] . revents & POLLBITS . POLLIN ) == POLLBITS . POLLIN )
288
297
{
289
- continue ;
298
+ break ;
290
299
}
291
- throw new ArgumentException (
292
- $ "FlashCap: Couldn't dequeue video buffer: Code={ code } , DevicePath={ this . devicePath } ") ;
293
- }
294
-
295
- this . frameProcessor . OnFrameArrived (
296
- this ,
297
- this . pBuffers [ buffer . index ] ,
298
- ( int ) buffer . bytesused ,
299
- // buffer.timestamp is untrustworthy.
300
- this . counter . ElapsedMicroseconds ,
301
- this . frameIndex ++ ) ;
302
-
303
- if ( ioctl ( this . fd , Interop . VIDIOC_QBUF , buffer ) < 0 )
304
- {
305
- // Couldn't get, maybe discarding.
306
- if ( Marshal . GetLastWin32Error ( ) is { } code && IsIgnore ( code ) )
300
+ if ( ( fds [ 1 ] . revents & POLLBITS . POLLIN ) == POLLBITS . POLLIN )
307
301
{
308
- continue ;
302
+ if ( ioctl ( this . fd , Interop . VIDIOC_DQBUF , buffer ) < 0 )
303
+ {
304
+ // Couldn't get, maybe discarding.
305
+ if ( Marshal . GetLastWin32Error ( ) is { } code && IsIgnore ( code ) )
306
+ {
307
+ continue ;
308
+ }
309
+
310
+ throw new ArgumentException (
311
+ $ "FlashCap: Couldn't dequeue video buffer: Code={ code } , DevicePath={ this . devicePath } ") ;
312
+ }
313
+
314
+ try
315
+ {
316
+ this . frameProcessor . OnFrameArrived (
317
+ this ,
318
+ this . pBuffers [ buffer . index ] ,
319
+ ( int ) buffer . bytesused ,
320
+ // buffer.timestamp is untrustworthy.
321
+ this . counter . ElapsedMicroseconds ,
322
+ this . frameIndex ++ ) ;
323
+ }
324
+ // DANGER: Stop leaking exception around outside of unmanaged area...
325
+ catch ( Exception ex )
326
+ {
327
+ Trace . WriteLine ( ex ) ;
328
+ }
329
+
330
+ if ( ioctl ( this . fd , Interop . VIDIOC_QBUF , buffer ) < 0 )
331
+ {
332
+ // Couldn't get, maybe discarding.
333
+ if ( Marshal . GetLastWin32Error ( ) is { } code && IsIgnore ( code ) )
334
+ {
335
+ continue ;
336
+ }
337
+
338
+ throw new ArgumentException (
339
+ $ "FlashCap: Couldn't enqueue video buffer: Code={ code } , DevicePath={ this . devicePath } ") ;
340
+ }
309
341
}
310
- throw new ArgumentException (
311
- $ "FlashCap: Couldn't enqueue video buffer: Code={ code } , DevicePath={ this . devicePath } ") ;
312
342
}
313
343
}
314
344
}
345
+ catch ( Exception ex )
346
+ {
347
+ Trace . WriteLine ( ex ) ;
348
+ }
315
349
finally
316
350
{
351
+ for ( var index = 0 ; index < pBuffers . Length ; index ++ )
352
+ {
353
+ if ( this . pBuffers [ index ] != default &&
354
+ this . bufferLength [ index ] != default )
355
+ {
356
+ munmap ( this . pBuffers [ index ] , ( ulong ) this . bufferLength [ index ] ) ;
357
+ this . pBuffers [ index ] = default ;
358
+ this . bufferLength [ index ] = default ;
359
+ }
360
+ }
361
+
317
362
close ( this . abortrfd ) ;
318
363
close ( this . fd ) ;
364
+
319
365
NativeMethods . FreeMemory ( this . pBih ) ;
366
+
320
367
this . abortrfd = - 1 ;
321
368
this . fd = - 1 ;
322
369
this . pBih = IntPtr . Zero ;
0 commit comments