Skip to content

Commit ce639ea

Browse files
author
Andrey Kalugin
committed
Stability improved.
1 parent 6724ace commit ce639ea

File tree

4 files changed

+46
-32
lines changed

4 files changed

+46
-32
lines changed

CameraLib/FlashCap/UsbCameraFc.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class UsbCameraFc : ICamera
2828
private readonly object _getPictureThreadLock = new();
2929
private readonly Stopwatch _fpsTimer = new();
3030
private byte _frameCount;
31-
private readonly System.Timers.Timer _keepAliveTimer = new System.Timers.Timer();
31+
private readonly System.Timers.Timer _keepAliveTimer = new();
3232
private int _width = 0;
3333
private int _height = 0;
3434
private string _format = string.Empty;
@@ -53,10 +53,10 @@ public UsbCameraFc(string path, string name = "")
5353
Description = new CameraDescription(CameraType.USB_FC, path, name, GetAllAvailableResolution(_usbCamera));
5454
CurrentFps = Description.FrameFormats.FirstOrDefault()?.Fps ?? 10;
5555

56-
_keepAliveTimer.Elapsed += CameraDisconnected;
56+
_keepAliveTimer.Elapsed += CheckCameraDisconnected;
5757
}
5858

59-
private async void CameraDisconnected(object? sender, ElapsedEventArgs e)
59+
private async void CheckCameraDisconnected(object? sender, ElapsedEventArgs e)
6060
{
6161
if (_fpsTimer.ElapsedMilliseconds > FrameTimeout)
6262
{
@@ -88,7 +88,7 @@ public static List<CameraDescription> DiscoverUsbCameras()
8888
return result;
8989
}
9090

91-
private static IEnumerable<FrameFormat> GetAllAvailableResolution(CaptureDeviceDescriptor usbCamera)
91+
private static List<FrameFormat> GetAllAvailableResolution(CaptureDeviceDescriptor usbCamera)
9292
{
9393
var formats = new List<FrameFormat>();
9494
foreach (var cameraCharacteristic in usbCamera.Characteristics)
@@ -167,14 +167,14 @@ public async Task<bool> Start(int width, int height, string format, Cancellation
167167
}
168168
else
169169
{
170-
characteristics = new List<VideoCharacteristics>(){
170+
characteristics = [
171171
characteristics.Aggregate((n, m) =>
172172
{
173173
if (n.Width * n.Height > m.Width * m.Height)
174174
return n;
175175
else
176176
return m;
177-
})};
177+
})];
178178
}
179179

180180
return characteristics.FirstOrDefault();
@@ -244,6 +244,7 @@ private void Stop(bool cancellation)
244244

245245
lock (_getPictureThreadLock)
246246
{
247+
IsRunning = false;
247248
_keepAliveTimer.Stop();
248249

249250
if (cancellation)

CameraLib/IP/IpCamera.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,10 @@ public IpCamera(string path,
161161
Description = new CameraDescription(CameraType.IP, path, name, frameFormats);
162162
CurrentFps = Description.FrameFormats.FirstOrDefault()?.Fps ?? 10;
163163

164-
_keepAliveTimer.Elapsed += CameraDisconnected;
164+
_keepAliveTimer.Elapsed += CheckCameraDisconnected;
165165
}
166166

167-
private async void CameraDisconnected(object? sender, ElapsedEventArgs e)
167+
private async void CheckCameraDisconnected(object? sender, ElapsedEventArgs e)
168168
{
169169
if (_fpsTimer.ElapsedMilliseconds > FrameTimeout)
170170
{
@@ -229,7 +229,8 @@ public async Task<bool> Start(int width, int height, string format, Cancellation
229229
catch (Exception ex)
230230
{
231231
Console.WriteLine($"Error getting image from camera: {ex}");
232-
await Task.Delay(1000);
232+
Stop();
233+
//await Task.Delay(1000);
233234
}
234235

235236
IsRunning = false;
@@ -309,14 +310,15 @@ private void Stop(bool cancellation)
309310

310311
lock (_getPictureThreadLock)
311312
{
313+
IsRunning = false;
312314
_keepAliveTimer.Stop();
313315

314316
if (_captureDevice != null)
315317
{
316318
_cancellationTokenSourceCameraGrabber?.Cancel();
317-
_captureTask?.Wait(5000);
318319
try
319320
{
321+
_captureTask?.Wait(5000);
320322
_captureDevice?.Release();
321323
}
322324
catch (Exception ex)
@@ -449,6 +451,7 @@ protected virtual void Dispose(bool disposing)
449451
_keepAliveTimer.Dispose();
450452
_captureDevice?.Dispose();
451453
_cancellationTokenSource?.Dispose();
454+
_cancellationTokenSourceCameraGrabber?.Dispose();
452455
}
453456

454457
_disposedValue = true;

CameraLib/MJPEG/MjpegCamera.cs

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ public class MjpegCamera : ICamera
3636
public CancellationToken CancellationToken => _cancellationTokenSource?.Token ?? CancellationToken.None;
3737

3838
private CancellationTokenSource? _cancellationTokenSource;
39-
private readonly object _getPictureThreadLock = new();
39+
private CancellationTokenSource? _cancellationTokenSourceCameraGrabber;
40+
private readonly object _getPictureThreadLock = new object();
4041
private Task? _imageGrabber;
41-
private volatile bool _stopCapture = false;
4242
private readonly Stopwatch _fpsTimer = new();
4343
private volatile byte _frameCount;
4444
private readonly System.Timers.Timer _keepAliveTimer = new();
@@ -93,10 +93,10 @@ public MjpegCamera(string path,
9393
Description = new CameraDescription(CameraType.IP, path, name, frameFormats);
9494
CurrentFps = Description.FrameFormats.FirstOrDefault()?.Fps ?? 10;
9595

96-
_keepAliveTimer.Elapsed += CameraDisconnected;
96+
_keepAliveTimer.Elapsed += CheckCameraDisconnected;
9797
}
9898

99-
private async void CameraDisconnected(object? sender, ElapsedEventArgs e)
99+
private async void CheckCameraDisconnected(object? sender, ElapsedEventArgs e)
100100
{
101101
if (_fpsTimer.ElapsedMilliseconds > FrameTimeout)
102102
{
@@ -135,17 +135,20 @@ public async Task<bool> Start(int width, int height, string format, Cancellation
135135
_height = height;
136136
_format = format;
137137

138+
_cancellationTokenSource?.Dispose();
138139
_cancellationTokenSource = new CancellationTokenSource();
140+
_cancellationTokenSourceCameraGrabber?.Dispose();
141+
_cancellationTokenSourceCameraGrabber = new CancellationTokenSource();
142+
139143
_frameCount = 0;
140144
_fpsTimer.Reset();
141145
_keepAliveTimer.Interval = FrameTimeout;
142146
_keepAliveTimer.Start();
143147

144-
_stopCapture = false;
145148
try
146149
{
147150
_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);
149152
}
150153
catch (Exception ex)
151154
{
@@ -172,11 +175,18 @@ private void Stop(bool cancellation)
172175

173176
lock (_getPictureThreadLock)
174177
{
178+
IsRunning = false;
175179
_keepAliveTimer.Stop();
176180

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+
}
180190

181191
if (cancellation)
182192
_cancellationTokenSource?.Cancel();
@@ -247,18 +257,16 @@ public async IAsyncEnumerable<Mat> GrabFrames([EnumeratorCancellation] Cancellat
247257
/// <param name="chunkMaxSize">Max chunk byte size when reading stream</param>
248258
/// <param name="frameBufferSize">Maximum frame byte size</param>
249259
/// <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)
251261
{
252-
var tokenLocal = token ?? CancellationToken.None;
253-
254262
using (var httpClient = new HttpClient())
255263
{
256264
if (authenicationType == AuthType.Basic)
257265
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
258266
"Basic",
259267
Convert.ToBase64String(Encoding.ASCII.GetBytes($"{login}:{password}")));
260268

261-
await using (var stream = await httpClient.GetStreamAsync(url, tokenLocal).ConfigureAwait(false))
269+
await using (var stream = await httpClient.GetStreamAsync(url, token).ConfigureAwait(false))
262270
{
263271
var streamBuffer = new byte[chunkMaxSize]; // Stream chunk read
264272
var frameBuffer = new byte[frameBufferSize]; // Frame buffer
@@ -272,17 +280,18 @@ private async Task StartAsync(string url, AuthType authenicationType, string log
272280
IsRunning = true;
273281
try
274282
{
275-
while (!_stopCapture && !tokenLocal.IsCancellationRequested)
283+
while (!token.IsCancellationRequested)
276284
{
277-
var streamLength = await stream.ReadAsync(streamBuffer.AsMemory(0, chunkMaxSize), tokenLocal)
285+
var streamLength = await stream.ReadAsync(streamBuffer.AsMemory(0, chunkMaxSize), token)
278286
.ConfigureAwait(false);
279287

280288
ParseStreamBuffer(frameBuffer, ref frameIdx, streamLength, streamBuffer, ref inPicture,
281-
ref previous, ref current, tokenLocal);
289+
ref previous, ref current, token);
282290
}
283291
}
284292
catch (Exception ex)
285293
{
294+
Stop();
286295
Console.WriteLine(ex);
287296
}
288297

@@ -295,7 +304,7 @@ private async Task StartAsync(string url, AuthType authenicationType, string log
295304
private void ParseStreamBuffer(byte[] frameBuffer, ref int frameIdx, int streamLength, byte[] streamBuffer, ref bool inPicture, ref byte previous, ref byte current, CancellationToken token)
296305
{
297306
var idx = 0;
298-
while (idx < streamLength && !_stopCapture && !token.IsCancellationRequested)
307+
while (idx < streamLength && !token.IsCancellationRequested)
299308
{
300309
if (inPicture)
301310
{
@@ -325,7 +334,7 @@ private void SearchPicture(byte[] frameBuffer, ref int frameIdx, ref int streamL
325334
inPicture = true;
326335
return;
327336
}
328-
} while (idx < streamLength && !_stopCapture && !token.IsCancellationRequested);
337+
} while (idx < streamLength && !token.IsCancellationRequested);
329338
}
330339

331340
// 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
384393

385394
return;
386395
}
387-
} while (idx < streamLength && !_stopCapture && !token.IsCancellationRequested);
396+
} while (idx < streamLength && !token.IsCancellationRequested);
388397
}
389398

390399
#endregion
@@ -437,11 +446,11 @@ protected virtual void Dispose(bool disposing)
437446
if (disposing)
438447
{
439448
Stop();
440-
_imageGrabber?.Wait(5000);
441449
_imageGrabber?.Dispose();
442450
_keepAliveTimer.Close();
443451
_keepAliveTimer.Dispose();
444452
_cancellationTokenSource?.Dispose();
453+
_cancellationTokenSourceCameraGrabber?.Dispose();
445454
}
446455

447456
_disposedValue = true;

CameraLib/USB/UsbCamera.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ public UsbCamera(string path, string name = "")
5353
Description = new CameraDescription(CameraType.USB, path, name, GetAllAvailableResolution(_usbCamera));
5454
CurrentFps = Description.FrameFormats.FirstOrDefault()?.Fps ?? 10;
5555

56-
_keepAliveTimer.Elapsed += CameraDisconnected;
56+
_keepAliveTimer.Elapsed += CheckCameraDisconnected;
5757
}
5858

59-
private async void CameraDisconnected(object? sender, ElapsedEventArgs e)
59+
private async void CheckCameraDisconnected(object? sender, ElapsedEventArgs e)
6060
{
6161
if (_fpsTimer.ElapsedMilliseconds > FrameTimeout)
6262
{
@@ -282,6 +282,7 @@ private void Stop(bool cancellation)
282282

283283
lock (_getPictureThreadLock)
284284
{
285+
IsRunning = false;
285286
_keepAliveTimer.Stop();
286287

287288
if (cancellation)

0 commit comments

Comments
 (0)