一、思维来源:
前几天在博客园看见了一个兄台写了一篇很够录制视频的软件,他的原理是利用一个timer控件不断的去获取桌面截图,然后保存到一个文件夹中,然后再按顺序读取保存的图片文件,通过设置timer的interval属性来播放图片,这样让人感觉效果就像放视频一样。
参考:http://www.cnblogs.com/im0330/p/3978798.html
二、自己的思路:
我觉得这位兄台将许多图片保存到一个文件夹中,如果视频需要录制很久,那么这个文件夹中保存的图片那的有多少,很不方便,如果能将同一个所有的图片放进同一个文件,那么看起来就好多了。有了这一想法之后我就开始打开我封存已久的vs2012,我是这样想的,界面上有三个按钮分别是“播放”,”停止“,”录制“,建立一个全局字节集合变量pRecordData,用他来存放我所获取的桌面截图的字节数。
录制视频的步骤如下:
- 1.扑捉桌面截图。
- 2.将桌面截图位图变为一个字节数组。
- 3.将该桌面截图的的字节数组的长度(int)转为一个字节数组。
- 4.先将桌面截图字节数组的长度(即4个单位的字节数组)保存到pRecordData中(方便读取),再将桌面截图的字节数组数据保存。
- 5.等视频录制结束直接将pRecordData集合中的字节全部写入到一个二进制文件中。
为什么要保存桌面截图的字节数组的长度,原因如下,我要将所有的截图全部要保存到这个文件中来,当然要为怎么去读取自己保存的数据考虑一下。通过用4个固定字节(即一个int型的整数)来保存存储实际桌面位图字节个数,这样就做在读取桌面截图的时候就不会乱码。
读取视频的步骤如下:
- 1.从保存的视频文件中读取所有的字节保存到pRecordData中。
- 2.将pRecordData提取四个字节转为整数,获取第一张位图的字节个数。i下标加4,。
- 3.从i+4个下标开始读取步骤一所获取的字节数,这样第一张图片就读取出来,i指针继续增加。
- 4.重复2、3步骤,就可以将所有的位图数据全部读取出来。
心想这个想法应该可行,于是就开始动手了,!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(省略几小时)
呀,终于把代码写好,激动的按下F5,点击开始录制,自己便各种在屏幕上乱点(假装在录制视频),等到1分钟左右,电脑突然卡卡~~~~~~~~~~~~~~~的叫,任我鼠标如何点,都没有用了,哎,我当时就觉得,内存可能不足了,电脑都没反应了,没办法啊,好苦逼啊,只能强行关机了。关机之后,我再次打开,我不死心,又调试一次,这次学乖了,先在录制视频函数里面插了一个断点看了一下,发现每次获取一次桌面图片pRecordData的count会增加4196406个字节,我的乖乖,这么多,我设置的timer的间隔是100毫秒,也就是说,每一秒就是大概1000万个字节,然后~~~就没然后了,我没有再想了,于是自己的内心对这次尝试宣判死刑了。很晚了,准备睡觉,想第二天来继续弄。
昨天睡觉没有睡好,一直都在思考如何解决内存的问题,今天早上起来又将这个不甘心的项目打开,把代码看来看,脑海里就一直问自己,“程序占内存是因为我将每次将捕捉过来的桌面面图都储存在内存,这样储存的越多,电脑不卡死才怪了,既然不能储存到内存,那我应该储存在哪里呢?”这样在心底的反复问自己,很快,就有点小思路了,将每次保存的位图都写入到一个临时文件中去,这样就不会照成内存爆满了,电脑卡机了。
三、改进之后的思路:
- 1.首先建立一个临时的二进制文件。
- 2.每次获取的一个桌面位图,都将位图写入到临时文件中去
有了这一个思路之后,我就开始动手写代码了,写到中午,粗略的代码终于写好了,我便开始调试了,录制的时间到了30多秒的时候,我发现内存和cpu的参数还是比较正常的,一看磁盘,不得了啊,居然占了100%,保存的临时文件也有1个多G。看到这样的数据之后我又沉默了。
虽然说这次尝试又是以失败告终,但是比上次的还是进步了不少,至少在录制3分钟以内的用来记录一下瞬时的东西还是可以的。不会让自己的电脑直接卡死了。
其中还有一处改进的地方,
就是在每次保存一帧桌面位图的前面都用了四个字节来保存该位图所有占的字节数,其实是没有必要,因为每次都是截取同一个桌面的位图,同样的大小而且每次捕捉的桌面位图都是一样,所以只需要用文件的最前面用四个字节保存位图的长度即可,然后后面每次定长的读取一段字节数据就行了,这样就能省一些内存。不过还是起不到什么大的作用。
四、待改进的地方(自己的想法,不知道是否可行)
- 1.在每次写入数据的时候可以将先将每个位图文件经行压缩然后再写入到文件中去,读取的时候经行解压就行了,c#有自带这样的类库,这样能够将数据量从1个多G减少到100M,甚至更少(我没尝试了)
- 2.不要频繁的写入和读取文件,每次多读取一点和多写入一点字节。综合前面的两个思路,还是在程序中建立一个pRecordData字节集合,每次将压缩后的桌面位图写入到pRecordData中去,然后判断pRecordData中的数据是否达到了一定量,如果达到了再写入到临时文件中去,这样就达到了无需频繁的读取磁盘了。
通过这两个思路可能就会解决文件的大小和运行时占用磁盘利用率的问题。
四、总结一下
1.这次做的视频软件不可以录制声音信息。
2.还有需要可能改进的地方,由于这段时间还需要忙着复习,所以没时间再去尝试了,以后有时间再去尝试
3.学习了BitConverter类库的使用,加强了MemoryStream类库的使用。(其中的主要作用是实现将基础数据类型与字节数组相互转换。)
下面是位图变为字节,字节变为位图的关键代码
/// <summary> /// 将位图转为内存流 /// </summary> /// <param name="btm"></param> /// <returns></returns> private byte[] BtmToByte(Bitmap btm) { using (MemoryStream ms = new MemoryStream()) { btm.Save(ms,System.Drawing .Imaging .ImageFormat .Bmp); return ms.ToArray(); } } /// <summary> /// 将字节数组生成位图 /// </summary> /// <param name="data">字节数组</param> /// <returns></returns> private Bitmap ByteToBtm(byte[] data) { Bitmap btm; using (MemoryStream ms = new MemoryStream(data)) { btm = Image.FromStream(ms) as Bitmap; } return btm; }
如果有新手看到这篇文章,想要一起交流一下,需要源代码的话,可以在下面留一下邮箱,我将会尽快给您发送的。
如果有高手看到这篇文章,还请不吝赐教,(发现我的不足,或提供一个可行的方案)在下感激万分。