10

I am currently working with AForge, and have an on new frame event that posts the frame, as a bitmap, into a picturebox. 90% of the time it works great... UNLESS I fiddle with something on the winform. Changing a combo box, moving the window, or anything like that risks causing the Picturebox to switch from the video to a big red X. Code sample below:

    private void connectButton_Click(object sender, EventArgs e)
    {
        try
        {
            cam = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);
            cam.NewFrame -= Handle_New_Frame; //Just to avoid the possibility of a second event handler being put on
            cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame);
            cam.Start();
        }
        catch
        {
            MessageBox.Show("An error has occured with connecting to the specified webcam. The application will now close!");
            Application.Exit();
        }
    }

    private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
    {

        try
        {
            if (bitmap != null)
                bitmap.Dispose(); //Without this, memory goes nuts
            bitmap = new Bitmap(eventArgs.Frame);
        }
        catch { }

        //Draw some stuff on the images
        bitmap = AdjustBrightness(bitmap, brightnessMeter);
        bitmap = ApplyContrast(contrastMeter, bitmap);
        bitmap = Draw_Top_Line(bitmap);
        bitmap = Draw_Bottom_Line(bitmap);

        //Set the image into the picturebox
        this.Invoke((MethodInvoker)delegate
        {
            videoPictureBox1.Image = bitmap;
            frameRate++; //Keep track of the frame rate
        });

        GC.Collect(); //Without this, memory goes nuts

        this.Invoke((MethodInvoker)delegate {
            videoPictureBox1.Refresh(); //NOT NECESSARY. JUST TRYING TO FIX THE BIG RED X!
        });

        if (videoPictureBox1.Image == videoPictureBox1.ErrorImage)
        {
            cam.Stop(); //ALSO NOT NECESSARY> AGAIN, JUST TRYING TO FIX THE BIG RED X!
            cam.Start();
        }
    }

I put a break on the if (videoPictureBox1.Image == videoPictureBox1.ErrorImage) and it is evaluating to false, even when the big red X is up, because the image is actually being set to the bitmap. So cam.Stop() and cam.Start() never run (not sure if that would even help, but I figured I would give it a try).

videoPictureBox1.Refresh() is running every time, but again- it's not making a difference. Still have the big red X.

As I said before: if I start the video and touch nothing, the big red X will never happen. But the moment I start changing combo boxes, or dragging the form itself around, the chance of the big red X goes up exponentially. Sometimes I can flip through the combo box 10-12 times before it happens, other times it happens the second I click the combobox. :-\

Can anyone explain what is happening here and perhaps offer a suggestion on the best method to go about fixing it? I'm still very new to threading, so I've been struggling to wrap my head around exactly what is happening here and the best way to fix the issue! Any nudges in the right direction would be a huge help!

C Smith
  • 778
  • 2
  • 14
  • 31
  • 1
    I think I'd probably just not use a picture box. Use a panel instead and draw the bitmap in the paint event of the panel. Forcing a refresh with invalidate. – James Apr 17 '13 at 13:19
  • Have you had a look at the eventArgs.Frame during the big red X senario? Also I would put a messagebox under that exception just in case that is where the error occurs. – TheKingDave Apr 17 '13 at 13:20
  • Alright, I'll give that a try really quick! An additional note: I went to debug -> exceptions and checked all the "Thrown" checkboxes. Nothing throws when that happens. At all. – C Smith Apr 17 '13 at 13:21
  • KingDave, I'll give that a try right now as well! Thanks! – C Smith Apr 17 '13 at 13:22
  • I added a panel changed "videoPictureBox1.Image = bitmap" to "panel3.BackGroundImage = bitmap; panel3.Invalidate();". I got the big red X again when moving the form around :( I also added a message in that catch- it was never called! It's a confusing little bug I've introduced! If only fixing it was as easy as creating it lol! – C Smith Apr 17 '13 at 13:28
  • I checked the contents of eventArgs.Frame while the Red X is up, and it is the image that it is supposed to be pulling (or at least appears to be. It's of the proper height/width/resolution). – C Smith Apr 17 '13 at 13:32

4 Answers4

6

In the end, I wrapped EVERYTHING in in the Handle_New_Frame in an invoke. It completely removed the big red X issue, permanently. >_>

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
  this.Invoke((MethodInvoker)delegate
  {
    try
    {
        if (bitmap != null)
        {
            bitmap.Dispose(); //Without this, memory goes nuts
        }

        bitmap = new Bitmap(eventArgs.Frame);
    }
    catch { }

    //Draw some stuff on the images
    bitmap = AdjustBrightness(bitmap, brightnessMeter);
    bitmap = ApplyContrast(contrastMeter, bitmap);
    bitmap = Draw_Top_Line(bitmap);
    bitmap = Draw_Bottom_Line(bitmap);

    //Set the image into the picturebox
    this.Invoke((MethodInvoker)delegate
    {
        videoPictureBox1.Image = bitmap;
        frameRate++; //Keep track of the frame rate
    });

    GC.Collect(); //Without this, memory goes nuts
  });
}
redspidermkv
  • 503
  • 10
  • 25
C Smith
  • 778
  • 2
  • 14
  • 31
  • I ran into the exact same thing and also tried to figure out what's going on, to no avail. I guess it some single-thread policy, but I as I could get no exceptions or errormessages whatsoever, I went with your approach and now it works. – Xan-Kun Clark-Davis Mar 11 '17 at 14:38
  • hi, i used it, but when i try to close videoSource it doesn t stop and stay wait to release the resource...have you got the same problem? – elle0087 Oct 23 '17 at 08:48
  • Regarding your comment on GC.Collect(). Bitmap's inheritance chain implements IDisposable. The GC issue is likely due you missing calling Dispose. Try a using block or manually call bitmap.Dispose(). – Micah Epps Apr 12 '19 at 00:47
6

Shawn Hargreaves has an excellent, concise writeup of the "big red X of doom". I found it very helpful in the general case of dealing with WinForm components suddenly showing the red "X".

In summary:

  • This is caused by a control throwing an exception out of the OnPaint event.
  • Once it is thrown, that control will continue to show the red X and skip firing OnPaint.
  • To debug, set the debugger to catch Common Language Runtime Exceptions, and then do whatever you normally do to get the red X. The debugger will stop right where it is happening, allowing you to investigate and hopefully figure out a way to prevent it.
Mark Meuer
  • 7,200
  • 6
  • 43
  • 64
1

try using the clone in places where you use the bitmap. Ex:

videoPictureBox1.Image = (Bitmap)bitmap.Clone();
Rafael Souza
  • 27
  • 10
0

Just to sum it up, this is a tested bare minimum that shows no red cross for me, even when resized, started, stoped or resolution changed.

   public partial class PictureBoxVideo : Form
   {
      public PictureBoxVideo()
      {
         InitializeComponent();
         var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
         var videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
         videoSource.NewFrame += Handle_Very_New_Frame;
         videoSource.Start();
      }

      private void Handle_Very_New_Frame(object sender, NewFrameEventArgs eventArgs)
      {
         this.Invoke((MethodInvoker)delegate {
            pictureBox.Image = new Bitmap(eventArgs.Frame);
         });
      }
   }

Please note, that we call videoSource.Start(); from the GUI-(creation)-thread, but the call back handler (Handle_Very_New_Frame) is called from the video (worker) thread.

I think that's why we need both, the Invoke and the new Bitmap, so the new bmp will also be generated from the gui-thread. But I'm just guessing here, as I couldn't come up with a proof.

Xan-Kun Clark-Davis
  • 2,664
  • 2
  • 27
  • 38