206 lines
6.8 KiB
C#
206 lines
6.8 KiB
C#
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; }
|
|
}
|
|
}
|