System.Drawing参数无效。

4
我目前在使用AForge dll将视频渲染到图片框中进行实时查看。我具有一个视频帧功能,可以将当前图片框帧作为JPG格式的WriteFrame或屏幕截图。但是,有时程序会提示“参数无效”或“对象已在其他地方使用”的错误。我尝试寻找解决方案,确信已对图像和克隆图像进行了处理,但问题仍然存在。您能帮助我确定我的程序哪里做错了吗?
void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            //your code using bmp object
            if (D1Pic.BackColor == Color.Green)
            {
                video = (Bitmap)eventArgs.Frame.Clone();
                if (livePreview.Image != null)
                {
                    //Dispose the resources
                    this.Invoke(new MethodInvoker(delegate() { livePreview.Image.Dispose(); }));
                }
                livePreview.Image = (Bitmap)eventArgs.Frame.Clone();
                imgclone = (Image)livePreview.Image.Clone();
                FileWriter.WriteVideoFrame(video);
            }
            else
            {
                video = (Bitmap)eventArgs.Frame.Clone();
                if (livePreview.Image != null)
                {
                    //Dispose the resources
                    this.Invoke(new MethodInvoker(delegate() { livePreview.Image.Dispose(); }));
                    this.Invoke(new MethodInvoker(delegate() { video.Dispose(); }));
                }
                livePreview.Image = (Bitmap)eventArgs.Frame.Clone();
                imgclone = (Image)livePreview.Image.Clone();
            }
            video.Dispose();
            livePreview.Refresh();

以下是堆栈跟踪错误:

{"Parameter is not valid."}
   at System.Drawing.Image.get_Width()
   at System.Windows.Forms.PictureBox.ImageRectangleFromSizeMode(PictureBoxSizeMode mode)
   at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

更新的代码:

 var newFrame = (Bitmap)eventArgs.Frame.Clone();
                this.Invoke(new MethodInvoker(delegate()
                {
                    if (livePreview.Image != null)
                    {
                        livePreview.Image.Dispose();
                    }
                    livePreview.Image = newFrame;
                }));
                imgclone = (Bitmap)eventArgs.Frame.Clone();

                //Write frame into video
                if (D1Pic.BackColor == Color.Green)
                {
                    video = (Bitmap)eventArgs.Frame.Clone();
                    FileWriter.WriteVideoFrame(video);
                }

错误发生在哪一行? - Jeremy Thompson
尝试使用 livePreview.Invalidate() - Jeremy Thompson
@JeremyThompson 我已经尝试使用livePreview和Invalidate()。过了一段时间后,程序仍然抛出“参数无效”的异常。 - Marcus
请发布完整的异常详细信息,并指出抛出异常的行。 - Blorgbeard
@Blorgbeard,我已经发布了错误信息。但它没有告诉我错误发生在哪一行,而只是从“Application.Run(new Main());”提示。 - Marcus
显示剩余2条评论
1个回答

7
您正在UI线程中调用livePreview.Image.Dispose(),但之后您没有将livePreview.Image设置为null。

因此,在您处置 livePreview.Image 并分配新图像之间的时间内, livePreview.Image 指向已处理的对象。

所以我认为偶尔您的picturebox尝试在此期间绘制自己,并在尝试访问其(已处理)Image属性时失败。

解决方案是:

if (livePreview.Image != null)
{
    //Dispose the resources
    this.Invoke(new MethodInvoker(delegate() { 
        livePreview.Image.Dispose(); 
        livePreview.Image = null;
    }));
}

甚至更好的是,在同一步骤中分配新图像:
var newFrame = (Bitmap)eventArgs.Frame.Clone();
this.Invoke(new MethodInvoker(delegate() { 
    if (livePreview.Image != null)
    {
        livePreview.Image.Dispose(); 
    }
    livePreview.Image = newFrame;
}));

通常情况下,您需要了解各种位图对象的情况。任何保留对已处理的位图的引用的内容都会成为问题。


视频录制的FileWriter也是一样的吗? - Marcus
我认为那部分没有问题,就我所看到的,所有操作都在同一个线程上进行。 - Blorgbeard
请查看我的更新代码,我已经对代码进行了更改。这样的代码可以吗? - Marcus
我在保存部分使用imgclone。你想看看吗?我将在imgClone.Save函数之后处理它。这会导致参数无效吗?目前我正在运行程序,让我们看看问题是否会出现。 - Marcus
它不应该引发ObjectDisposedException,因为您没有在另一个线程中处理它,所以(希望)您在处理后不会再访问它。video还在其他地方使用吗?我在您发布的代码中没有看到它被声明,所以我假设它是成员级别的字段,但是您在代码中对其进行了处理。 - Blorgbeard
让我们在聊天中继续这个讨论 - Marcus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接