@@ -36,9 +36,9 @@ public class MjpegCamera : ICamera
36
36
public CancellationToken CancellationToken => _cancellationTokenSource ? . Token ?? CancellationToken . None ;
37
37
38
38
private CancellationTokenSource ? _cancellationTokenSource ;
39
- private readonly object _getPictureThreadLock = new ( ) ;
39
+ private CancellationTokenSource ? _cancellationTokenSourceCameraGrabber ;
40
+ private readonly object _getPictureThreadLock = new object ( ) ;
40
41
private Task ? _imageGrabber ;
41
- private volatile bool _stopCapture = false ;
42
42
private readonly Stopwatch _fpsTimer = new ( ) ;
43
43
private volatile byte _frameCount ;
44
44
private readonly System . Timers . Timer _keepAliveTimer = new ( ) ;
@@ -93,10 +93,10 @@ public MjpegCamera(string path,
93
93
Description = new CameraDescription ( CameraType . IP , path , name , frameFormats ) ;
94
94
CurrentFps = Description . FrameFormats . FirstOrDefault ( ) ? . Fps ?? 10 ;
95
95
96
- _keepAliveTimer . Elapsed += CameraDisconnected ;
96
+ _keepAliveTimer . Elapsed += CheckCameraDisconnected ;
97
97
}
98
98
99
- private async void CameraDisconnected ( object ? sender , ElapsedEventArgs e )
99
+ private async void CheckCameraDisconnected ( object ? sender , ElapsedEventArgs e )
100
100
{
101
101
if ( _fpsTimer . ElapsedMilliseconds > FrameTimeout )
102
102
{
@@ -135,17 +135,20 @@ public async Task<bool> Start(int width, int height, string format, Cancellation
135
135
_height = height ;
136
136
_format = format ;
137
137
138
+ _cancellationTokenSource ? . Dispose ( ) ;
138
139
_cancellationTokenSource = new CancellationTokenSource ( ) ;
140
+ _cancellationTokenSourceCameraGrabber ? . Dispose ( ) ;
141
+ _cancellationTokenSourceCameraGrabber = new CancellationTokenSource ( ) ;
142
+
139
143
_frameCount = 0 ;
140
144
_fpsTimer . Reset ( ) ;
141
145
_keepAliveTimer . Interval = FrameTimeout ;
142
146
_keepAliveTimer . Start ( ) ;
143
147
144
- _stopCapture = false ;
145
148
try
146
149
{
147
150
_imageGrabber ? . Dispose ( ) ;
148
- _imageGrabber = StartAsync ( Description . Path , AuthenicationType , Login , Password , token ) . WaitAsync ( TimeSpan . FromMilliseconds ( FrameTimeout ) , token ) ;
151
+ _imageGrabber = StartAsync ( Description . Path , AuthenicationType , _cancellationTokenSourceCameraGrabber . Token , Login , Password ) . WaitAsync ( TimeSpan . FromMilliseconds ( FrameTimeout ) , token ) ;
149
152
}
150
153
catch ( Exception ex )
151
154
{
@@ -172,11 +175,18 @@ private void Stop(bool cancellation)
172
175
173
176
lock ( _getPictureThreadLock )
174
177
{
178
+ IsRunning = false ;
175
179
_keepAliveTimer . Stop ( ) ;
176
180
177
- _stopCapture = true ;
178
- var timeOut = DateTime . Now . AddSeconds ( 100 ) ;
179
- _imageGrabber ? . Wait ( 5000 ) ;
181
+ _cancellationTokenSourceCameraGrabber ? . Cancel ( ) ;
182
+ try
183
+ {
184
+ _imageGrabber ? . Wait ( 5000 ) ;
185
+ }
186
+ catch ( Exception ex )
187
+ {
188
+ Console . WriteLine ( $ "Camera Stop() failed: { ex } ") ;
189
+ }
180
190
181
191
if ( cancellation )
182
192
_cancellationTokenSource ? . Cancel ( ) ;
@@ -247,18 +257,16 @@ public async IAsyncEnumerable<Mat> GrabFrames([EnumeratorCancellation] Cancellat
247
257
/// <param name="chunkMaxSize">Max chunk byte size when reading stream</param>
248
258
/// <param name="frameBufferSize">Maximum frame byte size</param>
249
259
/// <returns></returns>
250
- private async Task StartAsync ( string url , AuthType authenicationType , string login = "" , string password = "" , CancellationToken ? token = null , int chunkMaxSize = 1024 , int frameBufferSize = 1024 * 1024 )
260
+ private async Task StartAsync ( string url , AuthType authenicationType , CancellationToken token , string login = "" , string password = "" , int chunkMaxSize = 1024 , int frameBufferSize = 1024 * 1024 )
251
261
{
252
- var tokenLocal = token ?? CancellationToken . None ;
253
-
254
262
using ( var httpClient = new HttpClient ( ) )
255
263
{
256
264
if ( authenicationType == AuthType . Basic )
257
265
httpClient . DefaultRequestHeaders . Authorization = new AuthenticationHeaderValue (
258
266
"Basic" ,
259
267
Convert . ToBase64String ( Encoding . ASCII . GetBytes ( $ "{ login } :{ password } ") ) ) ;
260
268
261
- await using ( var stream = await httpClient . GetStreamAsync ( url , tokenLocal ) . ConfigureAwait ( false ) )
269
+ await using ( var stream = await httpClient . GetStreamAsync ( url , token ) . ConfigureAwait ( false ) )
262
270
{
263
271
var streamBuffer = new byte [ chunkMaxSize ] ; // Stream chunk read
264
272
var frameBuffer = new byte [ frameBufferSize ] ; // Frame buffer
@@ -272,17 +280,18 @@ private async Task StartAsync(string url, AuthType authenicationType, string log
272
280
IsRunning = true ;
273
281
try
274
282
{
275
- while ( ! _stopCapture && ! tokenLocal . IsCancellationRequested )
283
+ while ( ! token . IsCancellationRequested )
276
284
{
277
- var streamLength = await stream . ReadAsync ( streamBuffer . AsMemory ( 0 , chunkMaxSize ) , tokenLocal )
285
+ var streamLength = await stream . ReadAsync ( streamBuffer . AsMemory ( 0 , chunkMaxSize ) , token )
278
286
. ConfigureAwait ( false ) ;
279
287
280
288
ParseStreamBuffer ( frameBuffer , ref frameIdx , streamLength , streamBuffer , ref inPicture ,
281
- ref previous , ref current , tokenLocal ) ;
289
+ ref previous , ref current , token ) ;
282
290
}
283
291
}
284
292
catch ( Exception ex )
285
293
{
294
+ Stop ( ) ;
286
295
Console . WriteLine ( ex ) ;
287
296
}
288
297
@@ -295,7 +304,7 @@ private async Task StartAsync(string url, AuthType authenicationType, string log
295
304
private void ParseStreamBuffer ( byte [ ] frameBuffer , ref int frameIdx , int streamLength , byte [ ] streamBuffer , ref bool inPicture , ref byte previous , ref byte current , CancellationToken token )
296
305
{
297
306
var idx = 0 ;
298
- while ( idx < streamLength && ! _stopCapture && ! token . IsCancellationRequested )
307
+ while ( idx < streamLength && ! token . IsCancellationRequested )
299
308
{
300
309
if ( inPicture )
301
310
{
@@ -325,7 +334,7 @@ private void SearchPicture(byte[] frameBuffer, ref int frameIdx, ref int streamL
325
334
inPicture = true ;
326
335
return ;
327
336
}
328
- } while ( idx < streamLength && ! _stopCapture && ! token . IsCancellationRequested ) ;
337
+ } while ( idx < streamLength && ! token . IsCancellationRequested ) ;
329
338
}
330
339
331
340
// While we are parsing a picture, fill the frame buffer until a FFD9 is reach.
@@ -384,7 +393,7 @@ private void ParsePicture(byte[] frameBuffer, ref int frameIdx, ref int streamLe
384
393
385
394
return ;
386
395
}
387
- } while ( idx < streamLength && ! _stopCapture && ! token . IsCancellationRequested ) ;
396
+ } while ( idx < streamLength && ! token . IsCancellationRequested ) ;
388
397
}
389
398
390
399
#endregion
@@ -437,11 +446,11 @@ protected virtual void Dispose(bool disposing)
437
446
if ( disposing )
438
447
{
439
448
Stop ( ) ;
440
- _imageGrabber ? . Wait ( 5000 ) ;
441
449
_imageGrabber ? . Dispose ( ) ;
442
450
_keepAliveTimer . Close ( ) ;
443
451
_keepAliveTimer . Dispose ( ) ;
444
452
_cancellationTokenSource ? . Dispose ( ) ;
453
+ _cancellationTokenSourceCameraGrabber ? . Dispose ( ) ;
445
454
}
446
455
447
456
_disposedValue = true ;
0 commit comments