当前位置:网站首页>C# wpf使用ffmpeg命令行实现录屏
C# wpf使用ffmpeg命令行实现录屏
2022-08-03 23:56:00 【CodeOfCC】
wpf截屏系列
第一章 使用GDI+实现截屏
第二章 使用DockPanel制作截屏框
第三章 实现截屏框实时截屏
第四章 使用ffmpeg命令行实现录屏(本章)
文章目录
前言
上一章我们实现了截屏界面与功能,接下来可以在此基础上实现录屏功能,录屏采用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子进程还是有不少细节需要处理的,比如进程自动退出、信息反馈、停止录屏、异常提示等。另外一方面在界面上也有需要处理的东西,比如可控的点击穿透、控制窗口置顶等等。总的来说,实现这一一个功能模块还是需要一定的时间和精力,以及一些相关的知识。
边栏推荐
猜你喜欢
随机推荐
POE交换机全方位解读(上)
POE交换机全方位解读(下)
MPLS Comprehensive Experiment
Three.js入门详解
射频芯片ATE测试从入门到放弃之参数测试
孙宇晨:Web3.0和元宇宙将协助人类更加全面地进入网络世界
MPLS综合实验
绕任意轴旋转矩阵推导
电子邮件安全或面临新威胁!
关于mnn模型输出的数据杂乱无章问题
用栈实现队列
【LeetCode】最长公共子序列(动态规划)
【杂项】通过Excel为字符串产生条码
栈的压入、弹出序列
It will invest about 200 billion US dollars in the United States in 20 years, and Samsung Electronics looks so handsome
libnet
一文搞定 SQL Server 执行计划
FastDFS 一文读懂
curl使用指南
单例模式使用饿汉式和懒汉式创建一定安全?很多人不知