目录
- 前言
- 一、主要步骤
- 1、使用 AllowsTransparency实现穿透框
- 2、获取音频设备名称
- 3、命令行启动ffmpeg
- 4、使用JobObject管理子进程
- 二、完整代码
- 三、效果预览
- 1、录制中
- 2、录制动态流程
- 总结
前言
上一章我们实现了截屏界面与功能,接下来可以在此基础上实现录屏功能,录屏采用ffmpeg命令行实现会方便一些,效果也是不错的,当然前提是要对Windows子进程的控制比较熟悉,做出来之后完全可以满足项目使用。
一、主要步骤
1、使用 AllowsTransparency实现穿透框
录屏需要使用AllowsTransparency来实现透明背景,因为录屏时框选区域需要能够点击穿透到桌面,使用WindowChome则不行。
2、获取音频设备名称
因为不依赖第三方工具(比如:screen capture recorder),只要我们能够获取音频设备名称就可以使用ffmpeg的dshow录制声音。我们通过调用Com的方式就可以获取到设备名称,在《C# 使用com获取Windows摄像头列表》的基础上添加一个属性获取音频设备列表:
static readonly Guid AudioInputDevice = new Guid(0x33d9a762, 0x90c8, 0x11d0, 0xbd, 0x43, 0x0, 0xa0, 0xc9, 0x11, 0xce, 0x86); /// <summary> /// 枚举录音设备 /// </summary> public static IEnumerable<string> AudioInputDevices { get { IMoniker[] monikers = new IMoniker[5]; var devEnum = Activator.CreateInstance(Type.GetTypeFromCLSID(SystemDeviceEnum)) as ICreateDevEnum; IEnumMoniker moniker; if (devEnum.CreateClassEnumerator(AudioInputDevice, out moniker, 0) == 0) { while (true) { int hr = moniker.Next(1, monikers, IntPtr.Zero); if (hr != 0 || monikers[0] == null) break; yield return GetName(monikers[0]); foreach (var i in monikers) { if (i != null) Marshal.ReleaseComObject(i); } } Marshal.ReleaseComObject(moniker); } Marshal.ReleaseComObject(devEnum); } }
获取音频设备名称
string audio = null; //获取音频采集设备名称 foreach (var i in EnumDevices.AudioInputDevices) { audio = i; break; }
3、命令行启动ffmpeg
得到了音频设备名称之后,我们就可以使用下面的命令行是实现录屏了。
录屏命令行,-i audio=上一步获取的音频设备名称。
ffmpeg -y -f dshow -sample_rate 44100 -sample_size 16 -channels 2 -i audio="麦克风 (Realtek High Definition Audio)" -f gdigrab -offset_x 10 -offset_y 20 -video_size 640x480 -i desktop -preset:v ultrafast -tune:v zerolatency -r 30 screen.mp4
启动ffmpeg(示例)
var process = new Process(); process.StartInfo.FileName = "ffmpeg"; process.StartInfo.Arguments ="-y -f dshow -sample_rate 44100 -sample_size 16 -channels 2 -i audio=\"麦克风 (Realtek High Definition Audio)\" -f gdigrab -offset_x 10 -offset_y 20 -video_size 640x480 -i desktop -preset:v ultrafast -tune:v zerolatency -r 30 screen.mp4 " process.Start()
4、使用JobObject管理子进程
启动ffmpeg作为子进程,需要对其进行一定的管理,要保证主进程任何情况的退出子进程跟随退出,我们可以使用Windows的JobObject实现这一功能。C#需要使用dllimport包装Job Object的WinApi。
下面是部分示例代码:创建了作业对象,并设置为对象销毁后,加入的进程全部退出。
handle = CreateJobObject(IntPtr.Zero, null); var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = 0x2000 }; var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = info }; int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error()));
二、完整代码
实现了录屏功能,包括画面和声音的录制,只依赖ffmpeg.exe。
之后上传
三、效果预览
1、录制中
2、录制动态流程
总结
以上就是今天要讲的内容了,因为使用了命令行所以录屏逻辑不用自己实现,但是要控制ffmpeg子进程还是有不少细节需要处理的,比如进程自动退出、信息反馈、停止录屏、异常提示等。另外一方面在界面上也有需要处理的东西,比如可控的点击穿透、控制窗口置顶等等。总的来说,实现这一一个功能模块还是需要一定的时间和精力,以及一些相关的知识。
到此这篇关于C# wpf使用ffmpeg命令行实现录屏的示例代码的文章就介绍到这了,更多相关C# wpf ffmpeg命令行录屏内容请搜索自由互联以前的文章或继续浏览下面的相关文章希望大家以后多多支持自由互联!