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; } } }