移动表单窗口时,屏幕录像机崩溃

时间:2018-08-29 19:45:28

标签: c# winforms

我遵循了一堆教程并制作了一个屏幕录像机。它可以通过截屏然后使用AForge.video插件将其转换为avi格式来工作。该程序运行正常,但大约20秒后内存不足。这将使程序崩溃或以巨大的延迟尖峰清除自身。为了阻止这种情况,我在每个屏幕截图的末尾添加了一种处置方法,以清除内存。这样可以减少内存使用量,但是会使应用程序变得非常不稳定。当我移动主窗口或等待录制大约3分钟时,程序崩溃并显示以下内容:
A screenshot of the error

每次删除dispose方法时,程序运行正常,但很快就会用完内存。也许我只是错误地使用了dispose方法。

这是使程序崩溃的代码。有很多代码可以将其全部包含在内。

 counter = 0;
 imagelist = new Bitmap[100000];
 Globals.imgcount = 0;
 Graphics g;

 basePath = sel.ToString();
 basePath = @"C:\Users\sim\Videos\Captures";
 using (var videowriter = new VideoFileWriter())
 {
     videowriter.Open(basePath + "timelapse.avi", Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, 9, VideoCodec.MPEG4, 1200000);

     while (Globals.recording == true) 
     {
         try
         {                       
             try
             {                      
                 //takes the screenshot                            
                 bm = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
                 //turns it into graphics
                 g = Graphics.FromImage(bm);
                 g.CopyFromScreen(0, 0, 0, 0, bm.Size);

                 counter++;                                    

                 videowriter.WriteVideoFrame(bm);

                 //display image
                 Bitmap original = bm;
                 Bitmap resized2 = new Bitmap(original, new Size(pictureBox1.Width, pictureBox1.Height));
                 bm = resized2;

                 pictureBox1.Image = bm;                                                       

                 Thread.Sleep(10);

                 if (/*counter % 18 == 0*/ true) 
                 {
                    try
                    {
                        g.Dispose();
                        bm.Dispose();

                        original.Dispose();
                        resized2.Dispose();
                    }
                    catch
                    {
                        MessageBox.Show("Disposal error");
                    }
                }
            }
            catch { }
        }
        catch { }
    }                
    videowriter.Close();
}

我希望这是足够的信息来解决问题。 感谢任何可以提供帮助的人。

1 个答案:

答案 0 :(得分:1)

您正在做许多不必要的事情,例如创建3个位图而不是一个,将图像 bm 设置为picbox,并确保将代码运行到主UI。当然,它将冻结。为了方便快捷地修复,请创建一个计时器。将间隔设置为10。创建一个button,它将停止计时器,并创建一个将启动它并进行记录。在计时器中而不是调用 反复

pictureBox1.Image = bm;

使用

pictureBox1.Invalidate();

代码:

//not good names. change it to something meaningfull
private Bitmap bm;
private Graphics g;
VideoFileWriter videowriter;

private void timer1_Tick( object sender, EventArgs e ) {;
    //takes the screenshot                            
    g.CopyFromScreen( 0, 0, 0, 0, bm.Size );

    videowriter.WriteVideoFrame(bm);

    pictureBox1.Invalidate();
}

开始录制的按钮:

private void Start_Click( object sender, EventArgs e ) {
    //create both bitmap and graphics once!
    bm = new Bitmap( Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height );
    g = Graphics.FromImage( bm );

    pictureBox1.Image = bm; //Just once!

    basePath = sel.ToString();
    basePath = @"C:\Users\sim\Videos\Captures";
    videowriter = new VideoFileWriter();
    videowriter.Open(basePath + "timelapse.avi", Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, 9, VideoCodec.MPEG4, 1200000);

    timer1.Enabled = true;
}

停止录制的按钮:

private void Stop_Click( object sender, EventArgs e ) {
    timer1.Enabled = false;

    pictureBox1.Image = null;
    bm.Dispose();
    bm = null;
    g.Dispose();
    g = null;
    videowriter.Close();
    //I don't know if videowriter can be disposed if so dispose it too and set it to null
}

还将picturebox SizeMode 设置为 StreachImage