我遵循了一堆教程并制作了一个屏幕录像机。它可以通过截屏然后使用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();
}
我希望这是足够的信息来解决问题。 感谢任何可以提供帮助的人。
答案 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