Files
PulsarK-main/Pulsar.Client/Helper/WebcamHelper.cs
T

206 lines
6.8 KiB
C#
Raw Normal View History

2026-08-27 10:57:58 -06:00
using AForge.Video;
using AForge.Video.DirectShow;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Threading;
namespace Pulsar.Client.Helper
{
public class WebcamHelper
{
private readonly object _lock = new object();
private Bitmap _currentFrame;
private bool _isRunning = false;
private VideoCaptureDevice _videoDevice;
private int _width;
private int _height;
private DateTime _lastFrameTime = DateTime.MinValue;
private readonly TimeSpan _frameInterval = TimeSpan.FromMilliseconds(33); // ~30fps
public void StartWebcam(int webcamIndex)
{
try
{
if (_isRunning) return;
FilterInfoCollection captureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
if (captureDevices.Count == 0)
{
Debug.WriteLine("No webcam detected.");
return;
}
if (webcamIndex < 0 || webcamIndex >= captureDevices.Count)
{
Debug.WriteLine("Invalid selection.");
return;
}
_videoDevice = new VideoCaptureDevice(captureDevices[webcamIndex].MonikerString);
var videoCapabilities = _videoDevice.VideoCapabilities;
if (videoCapabilities != null && videoCapabilities.Length > 0)
{
bool foundMatchingResolution = false;
foreach (var capability in videoCapabilities)
{
if (capability.AverageFrameRate >= 25 && capability.AverageFrameRate <= 35)
{
_videoDevice.VideoResolution = capability;
foundMatchingResolution = true;
Debug.WriteLine($"Selected video mode: {capability.FrameSize.Width}x{capability.FrameSize.Height} @ {capability.AverageFrameRate}fps");
break;
}
}
if (!foundMatchingResolution && videoCapabilities.Length > 0)
{
_videoDevice.VideoResolution = videoCapabilities[0];
Debug.WriteLine($"Selected default video mode: {videoCapabilities[0].FrameSize.Width}x{videoCapabilities[0].FrameSize.Height} @ {videoCapabilities[0].AverageFrameRate}fps");
}
}
_videoDevice.NewFrame += new NewFrameEventHandler(FinalFrame_NewFrame);
_videoDevice.VideoSourceError += VideoDevice_VideoSourceError;
_videoDevice.Start();
_isRunning = true;
}
catch (Exception ex)
{
Debug.WriteLine($"Error starting webcam: {ex.Message}");
}
}
public static string[] GetWebcams()
{
try
{
FilterInfoCollection captureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
string[] webcams = new string[captureDevices.Count];
for (int i = 0; i < captureDevices.Count; i++)
{
webcams[i] = captureDevices[i].Name;
}
return webcams;
}
catch (Exception ex)
{
Debug.WriteLine($"Error getting webcams: {ex.Message}");
return new string[0];
}
}
public void StopWebcam()
{
if (!_isRunning) return;
try
{
_videoDevice.SignalToStop();
_videoDevice.WaitForStop();
}
catch (Exception ex)
{
Debug.WriteLine($"Error stopping webcam: {ex.Message}");
}
finally
{
if (_videoDevice != null)
{
_videoDevice.NewFrame -= FinalFrame_NewFrame;
_videoDevice.VideoSourceError -= VideoDevice_VideoSourceError;
_videoDevice = null;
}
_isRunning = false;
}
}
public Bitmap GetLatestFrame()
{
DateTime now = DateTime.UtcNow;
lock (_lock)
{
try
{
if (_currentFrame == null)
return null;
if ((now - _lastFrameTime) >= _frameInterval)
{
_lastFrameTime = now;
return _currentFrame?.Clone() as Bitmap;
}
return null;
}
catch (Exception ex)
{
Debug.WriteLine($"Error getting latest frame: {ex.Message}");
return null;
}
}
}
public Bounds GetBounds()
{
lock (_lock)
{
try
{
return new Bounds { Width = _width, Height = _height };
}
catch (Exception ex)
{
Debug.WriteLine($"Error getting bounds: {ex.Message}");
return new Bounds { Width = 0, Height = 0 };
}
}
}
private void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
lock (_lock)
{
try
{
_currentFrame?.Dispose();
Bitmap frame = (Bitmap)eventArgs.Frame.Clone();
frame.RotateFlip(RotateFlipType.RotateNoneFlipX);
_currentFrame = frame;
_width = _currentFrame.Width;
_height = _currentFrame.Height;
}
catch (Exception ex)
{
Debug.WriteLine($"Error processing new frame: {ex.Message}");
}
}
}
private void VideoDevice_VideoSourceError(object sender, VideoSourceErrorEventArgs eventArgs)
{
var desc = eventArgs.Description ?? string.Empty;
if (desc.IndexOf("0x80004002", StringComparison.OrdinalIgnoreCase) >= 0 ||
desc.IndexOf("Interface not supported", StringComparison.OrdinalIgnoreCase) >= 0)
{
Debug.WriteLine("Webcam does not support required video control interface; ignoring.");
}
else
{
Debug.WriteLine($"Video source error: {desc}");
}
}
}
public struct Bounds
{
public int Width { get; set; }
public int Height { get; set; }
}
}