using OpenCvSharp; using System.Threading; namespace AIParkingApplication { public delegate void CameraEvent(Mat videoFrame); public class Camera { private string streamUrl; private volatile bool isFrameRequested; private Thread readStreamThread; private VideoCapture videoCapture; public volatile Mat CurrentFrame; public event CameraEvent OnVideoFrameReceived; public event CameraEvent OnOpenVideoStreamFailed; public Camera(string streamUrl) { this.streamUrl = streamUrl; isFrameRequested = false; videoCapture = new VideoCapture(); readStreamThread = new Thread(new ThreadStart(ReadVideoStream)); readStreamThread.IsBackground = true; } ~Camera() { Stop(); videoCapture?.Dispose(); } public void Start() { if (!readStreamThread.IsAlive) { readStreamThread = new Thread(new ThreadStart(ReadVideoStream)); readStreamThread.IsBackground = true; readStreamThread.Start(); } } public void RequestCaptureOneFrame() { isFrameRequested = true; } public void ReadVideoStream() { if (!videoCapture.Open(streamUrl)) { OnOpenVideoStreamFailed?.Invoke(Cv2.ImRead(AppConstant.CAMERA_FAILED_IMAGE_PATH)); return; } Mat videoFrame = new Mat(); while (true) { //Thread.Sleep(5); Thread.Sleep(50); //Stream Thread Sleep //Thread.Sleep(40); //Video Thread Sleep if (videoCapture.Read(videoFrame) && videoFrame.Width > 0 && videoFrame.Height > 0) { OnVideoFrameReceived?.Invoke(videoFrame); if (isFrameRequested) { CurrentFrame = videoFrame; isFrameRequested = false; } } else { OnOpenVideoStreamFailed?.Invoke(Cv2.ImRead(AppConstant.CAMERA_FAILED_IMAGE_PATH)); } } } public void Stop() { if (readStreamThread.IsAlive) { readStreamThread.Abort(); } } } }