Picturebox getting big red X but I can't detect or fix it

10,297

Solution 1

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

Solution 2

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.

Solution 3

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

videoPictureBox1.Image = (Bitmap)bitmap.Clone();
Share:
10,297
C Smith
Author by

C Smith

Updated on June 14, 2022

Comments

  • C Smith
    C Smith almost 2 years

    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!

    • James Barrass
      James Barrass about 11 years
      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.
    • TheKingDave
      TheKingDave about 11 years
      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.
    • C Smith
      C Smith about 11 years
      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
      C Smith about 11 years
      KingDave, I'll give that a try right now as well! Thanks!
    • C Smith
      C Smith about 11 years
      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
      C Smith about 11 years
      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).
  • Hans
    Hans about 11 years
    This could also lead to a race condition or am I wrong? If a redraw happens between disposing the bitmap and cloning the bitmap then the big red X will show up.
  • Rafael Souza
    Rafael Souza about 11 years
    @Hans yes, try using the bitmap before dispose()
  • Xan-Kun Clark-Davis
    Xan-Kun Clark-Davis about 7 years
    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
    Xan-Kun Clark-Davis about 7 years
    @Hans could you please check the code in my answer? I tried to generate such a race condition but was not able to.
  • Xan-Kun Clark-Davis
    Xan-Kun Clark-Davis about 7 years
    BTW: I abandoned this approach for obvious reasons quite quickly :-)
  • elle0087
    elle0087 over 6 years
    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
    elle0087 over 6 years
    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?
  • Micah Epps
    Micah Epps about 5 years
    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().
  • Tobias Knauss
    Tobias Knauss over 4 years
    Link broken. Updated Link: shawnhargreaves.com/blog/…
  • Mark Meuer
    Mark Meuer over 4 years
    @TobiasKnauss Thank you! I've updated the link in the answer.