I'm trying to take photos from my webcam every 3 seconds. But when I try to run the code I always get the above error. I searched through StackOverflow and found some solutions that suggested locking the resource. I thought I did it with a mutex but unfortunately, I still get the error. I think it has something to do with the bitmap but I don't know where and which bitmap.
This is the code:
//Here I declare global variables
FilterInfoCollection filterInfoCollection;
VideoCaptureDevice videoCaptureDevice;
Int16 INTERVAL;
string SAVESPACE;
private static Mutex mutex = new Mutex();
//Here I start the stream of my webcam from where I get my images
private void startNewCamera()
{
videoCaptureDevice = new VideoCaptureDevice(filterInfoCollection[comboBox_Cameras.SelectedIndex].MonikerString);
videoCaptureDevice.NewFrame = VideoCaptureDevice_NewFrame;
videoCaptureDevice.Start();
}
//from my understanding this is where the live stream is being generated
//I also locked this one with a mutex
private void VideoCaptureDevice_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
mutex.WaitOne();
pictureBox_Preview.Image = (Bitmap)eventArgs.Frame.Clone();
mutex.ReleaseMutex();
}
//Here I start with the backgroundworker from which I want to take a photo every 3 seconds
private void btn_Start_Click(object sender, EventArgs e)
{
//start recording
if (backgroundWorker_camera.IsBusy != true)
{
backgroundWorker_camera.RunWorkerAsync();
}
}
//This is where the magic happens
//I lock the whole function but the error occurs nevertheless
private void backgroundWorker_camera_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
while (!backgroundWorker_camera.CancellationPending)
{
System.Threading.Thread.Sleep(INTERVAL);
mutex.WaitOne();
//HERE THE ERROR ALWAYS OCCURS
pictureBox_Capture.Image = pictureBox_Preview.Image;
var bitmap = new Bitmap(pictureBox_Capture.Width, pictureBox_Capture.Height);
pictureBox_Capture.Invoke(new Action(() =>
{
pictureBox_Capture.DrawToBitmap(bitmap, pictureBox_Capture.ClientRectangle);
}));
System.Drawing.Imaging.ImageFormat imageFormat = null;
imageFormat = System.Drawing.Imaging.ImageFormat.Png;
mutex.ReleaseMutex();
}
}
If there is anything I can improve on my question please let me know. Thank you! :)
CodePudding user response:
I figured out the problem thanks to @NIRE GUPTAs' answer. Now I store the image in two separate variables for every thread. The updated functions look like this:
//New global Image variables for every thread
Image captureImageTH1;
Image captureImageTH2;
//The function where Livestream am commes from
private void VideoCaptureDevice_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
captureImageTH1 = (Bitmap)eventArgs.Frame.Clone();
captureImageTH2 = (Bitmap)eventArgs.Frame.Clone();
pictureBox_Preview.Image = captureImageTH1;
}
//The function where I capture the Image every 3 seconds
private void backgroundWorker_camera_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
string time;
while (!backgroundWorker_camera.CancellationPending)
{
System.Threading.Thread.Sleep(INTERVAL);
time = DateTime.Now.ToString("yyyy:MM:dd:HH:mm:ss");
pictureBox_Capture.Image = captureImageTH2;
var bitmap = new Bitmap(pictureBox_Capture.Width, pictureBox_Capture.Height);
pictureBox_Capture.Invoke(new Action(() =>
{
pictureBox_Capture.DrawToBitmap(bitmap, pictureBox_Capture.ClientRectangle);
}));
System.Drawing.Imaging.ImageFormat imageFormat = null;
imageFormat = System.Drawing.Imaging.ImageFormat.Png;
captureImageTH2.Save(Path.Combine(SAVESPACE, time ".png"));
}
As you can see I'm now trying to save the captured image. But every time I do It I get the following error:
System.Runtime.InteropServices.ExternalException: "A generic error occurred in GDI ."
What is it that I'm doing wrong now? This time as well the solutions from the internet didn't help.
CodePudding user response:
Images in GDI are not thread-safe. What it means, basically - you cannot use one image from 2 threads simultaneously without some additional changes to your code.