我是用winform做的,播放视频使用的是axWindowsMediaPlayer控件,我要实现的效果如下,截取视频图片--》 保存图片并为图片增加影视边框
下面我会贴出主要的实现代码
实现视频截图有两个方法:
1、使用ffmpeg实现
2、使用win32 API实现
ffmpeg实现视频截图
什么是ffmpeg?
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序,是多媒体视频处理工具。
ffmpeg有什么功能?
多媒体视频处理工具FFmpeg有非常强大的功能包括视频采集功能、视频格式转换、视频抓图、给视频加水印等。
ffmpeg使用
1、下载后解压,将bin文件下的文件复制粘贴到项目引用文件目录下
2、使用(两种使用方法)
①
//获取当前播放进度 string cutTime = axWindowsMediaPlayer1.Ctlcontrols.currentPositionString; string[] str = cutTime.Split(new char[] { ':' }); if (str.Length <= 0) //转成秒 int CutTimeFrame= 0; if (str.Length == 3) { CutTimeFrame= int.Parse(str[0]) * 60 * 60 + int.Parse(str[1]) * 60 + int.Parse(str[2]); } else if (str.Length == 2) { CutTimeFrame= int.Parse(str[0]) * 60 + int.Parse(str[1]); } else { CutTimeFrame= int.Parse(str[0]); } //视频中提取图片的命令 -r:每秒提取的帧数 -f:图片格式,上述为image2 -t:持续时间 -ss:起始时间,如-ss 01:30:14,从01:30:14开始 -vframes:指定抽取的帧数,如-vframes 120,指定抽取第120帧 -s:图片格式大小,如-s 640x360 -y:覆盖,如果指定保存的路径下文件名已存在,就直接覆盖 -q:v :图片质量
1 //截取指定时间的第一帧画面存为图片 2 string ffmpeg = Application.StartupPath + "\ffmpeg.exe"; 3 string PicName = @"D:VideoFFmpegImgvideo.png";//图片保存地址 4 System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(ffmpeg); 5 startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 6 startInfo.Arguments = " -i 视频路径 -ss "+CutTimeFrame+" -vframes 1 -s 100*60 -y " + PicName; //设定程序执行参数 7 System.Diagnostics.Process.Start(startInfo);
1 //截取指定时间相近的5张图 2 string ffmpeg = Application.StartupPath + "\ffmpeg.exe"; 3 for (int i = 0; i < 5; i++) 4 { 5 string PicName = @"D:VideoFFmpegImgvideo" + num.ToString() + name + ".png";//图片保存地址,自行定义 6 7 System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(ffmpeg); 8 startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 9 startInfo.Arguments = " -i " + VideoPath + " -ss " + (Convert.ToDouble(CutTimeFrame) + 0.2 * i) + " -vframes 1 -s 100*60 -y " + PicName; //设定程序执行参数 10 11 System.Diagnostics.Process.Start(startInfo); 12 num++; 13 }
截图语句:ffmpeg -i 视频地址 -ss 时间 -f image2 -frames 1 输出地址
这个命令会花费相当长的时间. 对一个清晰的或者较大的视频文件进行操作, 会花费半分钟以上. 截图的时间越往后, 花费的时间也越长。
出现这种情况的原因是由于参数的位置放置不正确造成的 "-ss" 要放在第一个参数位置: ffmpeg -ss 时间 -i 视频地址 -f image2 -y -frames 1
输出地址
②
另一种使用方法,直接设定程序执行参数
打开ffmpeg下载目录
输入cmd,回车。这里可以配置到环境变量,就不需要每次到ffmpeg的目录中打开了
在这里直接输入ffmpeg+ 空格 + 程序执行参数即可
ffmpeg -ss 00:02:06 -i D:视频video1008.mp4 -f image2 -y -frames 1 D: est1.jpg
使用win32 Api实现视频截图
1 //创建显示器的DC 2 [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")] 3 public static extern IntPtr CreateDC 4 ( 5 string Driver, //驱动名称 6 string Device, //设备名称 7 string Output, //无用,可以设定为null 8 IntPtr PrintData //任意的打印机数据 9 ); 10 11 12 [DllImport("user32.dll", EntryPoint = "FindWindow", CharSet = CharSet.Auto)] 13 public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);//寻找窗口列表中第一个符合指定条件的顶级窗口 14 //获得待测程序主窗体句柄 15 public static IntPtr FindMainWindowHandle(string caption, int delay, int maxTries) 16 { 17 IntPtr mwh = IntPtr.Zero; 18 bool formFound = false; 19 int attempts = 0; 20 while (!formFound && attempts < maxTries) 21 { 22 if (mwh == IntPtr.Zero) 23 { 24 Console.WriteLine("Form not yet found"); 25 Thread.Sleep(delay); 26 ++attempts; 27 mwh = FindWindow(null, caption); 28 } 29 else 30 { 31 Console.WriteLine("Form has been found"); 32 formFound = true; 33 } 34 } 35 if (mwh == IntPtr.Zero) 36 throw new Exception("Could not find main window"); 37 else 38 return mwh; 39 } 40 41 // 获得窗口矩形,包括非客户区 42 [DllImport("user32.dll")] 43 public static extern int GetWindowRect(IntPtr hWnd, out RECT lpRect); 44 // 矩形结构 45 [StructLayout(LayoutKind.Sequential)] 46 public struct RECT 47 { 48 public int Left;//坐标x 49 public int Top;//坐标y 50 public int Right;//宽 51 public int Bottom;//高 52 } 53 54 //从指定源设备上下文到目标设备上下文的像素矩形相对应的颜色数据的位块传输 55 [System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")] 56 public static extern bool BitBlt( 57 IntPtr hdcDest, //目标设备的句柄 58 int XDest, //目标对象的左上角X坐标 59 int YDest, //目标对象的左上角的Y坐标 60 int Width, //目标对象的宽度 61 int Height, //目标对象的高度 62 IntPtr hdcScr, //源设备的句柄 63 int XScr, //源设备的左上角X坐标 64 int YScr, //源设备的左上角Y坐标 65 Int32 drRop //光栅的操作值 66 ); 67 68 #region 截图 69 public void GetWin32PicFromVideo() 70 { 71 //创建显示器的DC 72 IntPtr dcScreen = CreateDC("DISPLAY", null, null, (IntPtr)null); 73 IntPtr mwh = FindMainWindowHandle("[F4]载入 [F5]截图", 100, 25); 74 //获取应用窗体大小 75 GetWindowRect(mwh, out RECT rect); 76 77 //要截取画面的坐标,可以自行调整 78 int x = rect.Left + 250; 79 int y = rect.Top + 35; 80 81 //836 470,截取大小 82 Graphics g1 = Graphics.FromHdc(dcScreen); 83 Image Myimage = new Bitmap(836, 470, g1); 84 Graphics g2 = Graphics.FromImage(Myimage); 85 IntPtr dc1 = g1.GetHdc(); 86 IntPtr dc2 = g2.GetHdc(); 87 88 BitBlt(dc2, 0, 0, 836, 470, dc1, x, y, 13369376); 89 g1.ReleaseHdc(dc1); 90 g2.ReleaseHdc(dc2); 91 92 //保存图片 93 Myimage.Save($@"D:Videosimg est.png"); 94 95 MessageBox.Show("保存成功!"); 96 97 } 98 99 100 #endregion