最近做 Windows 上的项目,客户要求要做的“炫”一点,所以,动态的窗口背景永远是必不可少的内容(比如手机qq的登录界面对吧?
我本以为这是一个很容易实现的功能于是就满口答应下来……是的,在 winform 里,并不是那么容易就能达到你想要的效果的。
理所当然,我们想到如果要播放视频,那么就用系统自带的 media player,只要添加一个控件就可以搞定——结果就是播放的视频要么被按钮挡住,要么就是永远在第一,把按钮挡住……
所以了,想要实现播放视频,还是要老老实实的使用 pictureBox 。
那么这就要用到所谓的 mciSendString 方法,比如说这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
private class LibWrap { [DllImport(("winmm.dll"), EntryPoint = "mciSendString", CharSet = CharSet.Auto)] public static extern int mciSendString(string lpszCommand, string lpszReturnString, uint cchReturn, IntPtr hwndCallback); } private void PlayViedo() { PictureBox PlayScreen = new PictureBox(); PlayScreen = this.pictureBox; string mciCommand; string path = string.Empty; path = System.Windows.Forms.Application.StartupPath + @"\Background"; if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } path += @"\bg.wmv"; mciCommand = "open " + path + " alias MyAVI"; mciCommand = mciCommand + " parent " + PlayScreen.Handle.ToInt32() + " style child"; LibWrap.mciSendString(mciCommand, null, 0, IntPtr.Zero); Rectangle r = PlayScreen.ClientRectangle; mciCommand = "put MyAVI window at 0 0 " + r.Width + " " + r.Height; LibWrap.mciSendString(mciCommand, null, 0, IntPtr.Zero); // LibWrap.mciSendString("play MyAVI", null, 0, IntPtr.Zero); LibWrap.mciSendString("play MyAVI repeat", null, 0, IntPtr.Zero); } |
但这个是不能用的,即使把官方的代码拷贝过来,也无法得到正确的结果——就是不播放你有脾气?
最终,我还是用 OpenCV 实现了这个效果,当然,给 C# 用,我们得找 OpenCV 的 .net 封装,也就是 EmguCV。
这里我就大略的记录一下实现过程,首先你要去下载 Emgu 库安装一下,地址在这里:https://sourceforge.net/projects/emgucv/files/emgucv/3.2/libemgucv-windesktop-3.2.0.2682.exe/download
你要注意下载的版本,如果有更新的版本,请下载新版。
原理
其实使用 emgu 的原理和上文用 pictureBox 播放视频应该是一致的,都是把视频按照时间获取帧,然后显示一张图片罢了。使用 emgu 的另外一个好处是它可以把任意视频做成这样,比如你的 mp4,或者是串流地址。
环境配置
下载安装后,默认的安装位置为: C:\Emgu\emgucv-windesktop 3.2.0.2682\bin 具体版本号可能会有变化。现在我们打开 vs,在里边导入 emgu:
-
- 点开你的程序项目,在「设计」模式下左侧的「工具箱」中点鼠标右键,选择「选择项…」;
- 在弹出的对话框中点下边的「浏览」,找到 emgu 的安装位置,选中 Emgu.CV.UI.dll、 ZedGraph.dll 这两个进行打开;
- VS 会自动导入并选中这些 emgu 的控件,确定即可;
- 在项目右侧的「解决方案资源管理器」中,找到「引用」,在里边点右键选择「添加引用」;
- 在弹出的对话框左侧选择「浏览」,然后手动导入 Emgu.CV.UI.dll、 ZedGraph.dll 、 Emgu.CV.UI.GL.dll 、 Emgu.CV.World.dll 这四个文件。
这样,环境就配置好了。
使用控件
这个时候你就可以从工具箱中拖入要用的 emgu 控件了,这里我们用 emgu 的 ImageBox ,拖入后把它命名为 VideoBox 备用。
这里我们要用到的类变量,注意声明在类中:
1 2 3 |
VideoCapture camCapter = null; Mat frame; System.Windows.Forms.Timer PlayerTimer = new System.Windows.Forms.Timer(); |
当要播放视频的时候,就这么做:
1 2 3 4 5 6 7 8 |
camCapter = new VideoCapture(videoUrl); VideoBox.Dock = DockStyle.Fill; camCapter.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.PosFrames, 2241); var tmp = (camCapter.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps) > 0) ? (camCapter.GetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps)) : 24; int delay = (int)(1000 / tmp); PlayerTimer.Interval = delay; PlayerTimer.Tick += VideoController; PlayerTimer.Start(); |
这里有两点需要注意:
- 第 4 行获取视频的帧率,并不是所有的视频都能正确获取到,所以如果不能获取,我们就给一个默认的 24 fps,当然,你也可以默认 25 或者 30;
- 第 8 行注意这里一定要调用启动,不然视频就不会播放了,不会自动启动计时器的。
现在我们再来看看 VideoController 的实现,这里最重要,因为计时器会在规定的时间轮询这个控制器,具体的显示操作就是由这个控制器来完成的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
void VideoController(object sender, EventArgs e) { if (camCapter == null) { return; } if (frame != null) { frame.Dispose(); } if (VideoPlayNeedsStop) { frame = null; PlayerTimer.Stop(); } frame = camCapter.QueryFrame(); if (frame == null) { Console.WriteLine("Video End"); //camCapter = new VideoCapture(videoUrl); //PlayerTimer.Stop(); return; } VideoBox.Image = frame; } |
注意如果你想要连续播放(重复循环播放),那么就在高亮的一行重新初始化一个 VideoCapture 就可以了。
加入透明背景的控件
当然,最后我们还要加入控件,比如说一个 Button ,你需要一个具有透明设定的 png 来作为按钮的内容,然后就做如下配置:
1 2 3 4 5 6 7 8 |
this.ll.Text = ""; this.ll.Image = ScreenController.ScreenController.shared.GetImageFrom("ui_images\\liulan.png"); this.ll.BackgroundImageLayout = ImageLayout.None; this.ll.FlatAppearance.BorderSize = 0; this.ll.FlatAppearance.MouseDownBackColor = Color.Transparent; this.ll.FlatAppearance.MouseOverBackColor = Color.Transparent; this.ll.FlatStyle = FlatStyle.Flat; this.ll.BackColor = Color.Transparent; |
这里 ll 是我的一个 Button ,总之,如此配置之后,按钮就是透明的了,但你会发现它虽然覆盖在视频之上,但显然透明到的还是窗口本身的背景而不是显示其下视频的内容。
1 |
this.ll.Parent = VideoBox; |
这时我们可以手动调整按钮的父级为这我们的 VideoBox ,这样,它就能显示出视频的内容了。
动态链接库
最后,你还需要把运行时依赖的动态链接库拷贝到程序的运行目录下,这个分为32位和64位,你如果是debug运行,就拷贝32位目录内的文件即可: C:\Emgu\emgucv-windesktop 3.2.0.2682\bin\x86
参考文献
- OpenCV
- Emgu CV: OpenCV in .NET (C#, VB, C++ and more)
- 如何使用PictureBox播放视频
- 【Emgu】一起学EmguCV(一)配置与使用
- VS2010+C#+EmguCV读取和录制视频
- [emguCV]播放影片—臨時筆記(未整理)
本文由 落格博客 原创撰写:落格博客 » winform 使用 视频 作为窗口背景
转载请保留出处和原文链接:https://www.logcg.com/archives/2893.html