fix: 修复摄像头无法正常启动,以及关闭摄像头会导致后端崩溃的问题
This commit is contained in:
@@ -3,7 +3,6 @@ using System.Text;
|
||||
using System.Collections.Concurrent;
|
||||
using DotNext;
|
||||
using DotNext.Threading;
|
||||
using FlashCap;
|
||||
|
||||
namespace server.Services;
|
||||
|
||||
@@ -108,7 +107,7 @@ public class HttpVideoStreamService : BackgroundService
|
||||
var devices = camera.GetDevices();
|
||||
for (int i = 0; i < devices.Count; i++)
|
||||
logger.Info($"Device[{i}]: {devices[i].Name}");
|
||||
await camera.StartAsync(1, 3840, 2160, 30);
|
||||
await camera.StartAsync(1, 2592, 1994, 30);
|
||||
return camera;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -120,14 +119,11 @@ public class HttpVideoStreamService : BackgroundService
|
||||
|
||||
private Optional<VideoStreamClient> TryGetClient(string boardId)
|
||||
{
|
||||
if (_clientDict.TryGetValue(boardId, out var client))
|
||||
{
|
||||
return client;
|
||||
}
|
||||
return null;
|
||||
return _clientDict.TryGetValue(boardId, out var client) ? client : null;
|
||||
}
|
||||
|
||||
private Optional<VideoStreamClient> GetOrCreateClient(string boardId, int initWidth, int initHeight)
|
||||
private Optional<VideoStreamClient> GetOrCreateClient(
|
||||
string boardId, int initWidth, int initHeight)
|
||||
{
|
||||
if (_clientDict.TryGetValue(boardId, out var client))
|
||||
{
|
||||
@@ -185,6 +181,8 @@ public class HttpVideoStreamService : BackgroundService
|
||||
{
|
||||
var client = _clientDict[clientKey];
|
||||
client.CTS.Cancel();
|
||||
if (!client.Camera.IsValueCreated) continue;
|
||||
|
||||
using (await client.Lock.AcquireWriteLockAsync(cancellationToken))
|
||||
{
|
||||
var camera = await client.Camera.WithCancellation(cancellationToken);
|
||||
@@ -251,26 +249,28 @@ public class HttpVideoStreamService : BackgroundService
|
||||
}
|
||||
|
||||
var client = clientOpt.Value;
|
||||
var token = CancellationTokenSource.CreateLinkedTokenSource(
|
||||
client.CTS.Token, cancellationToken).Token;
|
||||
|
||||
var clientToken = client.CTS.Token;
|
||||
try
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
logger.Info("新HTTP客户端连接: {RemoteEndPoint}", context.Request.RemoteEndPoint);
|
||||
|
||||
if (path == "/video")
|
||||
{
|
||||
// MJPEG 流请求(FPGA)
|
||||
await HandleMjpegStreamAsync(context.Response, client, cancellationToken);
|
||||
await HandleMjpegStreamAsync(context.Response, client, token);
|
||||
}
|
||||
else if (path == "/usbCamera")
|
||||
{
|
||||
// USB Camera MJPEG流请求
|
||||
await HandleUsbCameraStreamAsync(context.Response, client, cancellationToken);
|
||||
await HandleUsbCameraStreamAsync(context.Response, client, token);
|
||||
}
|
||||
else if (path == "/snapshot")
|
||||
{
|
||||
// 单帧图像请求
|
||||
await HandleSnapshotRequestAsync(context.Response, client, cancellationToken);
|
||||
await HandleSnapshotRequestAsync(context.Response, client, token);
|
||||
}
|
||||
else if (path == "/html")
|
||||
{
|
||||
@@ -300,10 +300,26 @@ public class HttpVideoStreamService : BackgroundService
|
||||
private async Task HandleUsbCameraStreamAsync(
|
||||
HttpListenerResponse response, VideoStreamClient client, CancellationToken cancellationToken)
|
||||
{
|
||||
var camera = await _usbCamera.WithCancellation(cancellationToken);
|
||||
|
||||
Action<byte[]> frameHandler = async (jpegData) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var header = Encoding.ASCII.GetBytes("--boundary\r\nContent-Type: image/jpeg\r\nContent-Length: " + jpegData.Length + "\r\n\r\n");
|
||||
await response.OutputStream.WriteAsync(header, 0, header.Length, cancellationToken);
|
||||
await response.OutputStream.WriteAsync(jpegData, 0, jpegData.Length, cancellationToken);
|
||||
await response.OutputStream.WriteAsync(new byte[] { 0x0D, 0x0A }, 0, 2, cancellationToken); // \r\n
|
||||
await response.OutputStream.FlushAsync(cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
logger.Error("Error sending MJPEG frame");
|
||||
}
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
var camera = await _usbCamera.WithCancellation(cancellationToken);
|
||||
|
||||
if (!camera.IsCapturing)
|
||||
{
|
||||
logger.Error("USB Camera is not capturing");
|
||||
@@ -320,32 +336,17 @@ public class HttpVideoStreamService : BackgroundService
|
||||
|
||||
logger.Info("Start USB Camera MJPEG Stream");
|
||||
|
||||
camera.FrameReady += frameHandler;
|
||||
|
||||
while (true)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var jpegData = camera.GetLatestFrame();
|
||||
if (jpegData == null)
|
||||
{
|
||||
logger.Warn("USB Camera MJPEG帧获取失败");
|
||||
await Task.Delay(1000 / client.FrameRate, cancellationToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
// MJPEG帧头
|
||||
var header = Encoding.ASCII.GetBytes("--boundary\r\nContent-Type: image/jpeg\r\nContent-Length: " + jpegData.Length + "\r\n\r\n");
|
||||
await response.OutputStream.WriteAsync(header, 0, header.Length, cancellationToken);
|
||||
await response.OutputStream.WriteAsync(jpegData, 0, jpegData.Length, cancellationToken);
|
||||
await response.OutputStream.WriteAsync(new byte[] { 0x0D, 0x0A }, 0, 2, cancellationToken); // \r\n
|
||||
await response.OutputStream.FlushAsync(cancellationToken);
|
||||
|
||||
await Task.Delay(1000 / client.FrameRate, cancellationToken);
|
||||
logger.Info("USB Camera MJPEG帧发送成功");
|
||||
await Task.Delay(-1, cancellationToken);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException ex)
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
logger.Info(ex, "USB Camera MJPEG 串流取消");
|
||||
logger.Info("USB Camera MJPEG 串流取消");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -353,7 +354,8 @@ public class HttpVideoStreamService : BackgroundService
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
camera.FrameReady -= frameHandler;
|
||||
logger.Info("Usb Camera Stream Stopped");
|
||||
try { response.Close(); } catch { }
|
||||
}
|
||||
}
|
||||
@@ -744,15 +746,14 @@ public class HttpVideoStreamService : BackgroundService
|
||||
|
||||
using (await client.Lock.AcquireWriteLockAsync())
|
||||
{
|
||||
if (enable)
|
||||
{
|
||||
client.CTS = new CancellationTokenSource();
|
||||
}
|
||||
else
|
||||
if (!enable || client.CTS.IsCancellationRequested)
|
||||
{
|
||||
client.CTS.Cancel();
|
||||
client.CTS = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
if (!client.Camera.IsValueCreated) return;
|
||||
|
||||
var camera = await client.Camera.WithCancellation(client.CTS.Token);
|
||||
var disableResult = await camera.EnableHardwareTrans(enable);
|
||||
if (disableResult.IsSuccessful && disableResult.Value)
|
||||
@@ -763,7 +764,7 @@ public class HttpVideoStreamService : BackgroundService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error(ex, $"Exception occurred while disabling HDMI transmission for camera {boardId}");
|
||||
logger.Error(ex, $"Exception occurred while disabling video transmission for {boardId}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user