前言
本文只考虑在Windows下使用FFmpeg进行桌面、麦克风、扬声器同时录制的实现方式,Mac下会有些许差异。
之前的FFmpeg有很多问题,现在随着版本的更新基本上都可以解决了,可以使用在项目中。
下载地址
官方只有64位
https://ffmpeg.org/download.html
非官方编译的32位
https://github.com/sudo-nautilus/FFmpeg-Builds-Win32/releases
代码示例:
https://gitee.com/psvmc/z-screen-recorder
FFMPEG的弊端
先说一下使用FFMpeg录制的弊端
- 需要引用ffmpeg.exe 文件本身比较大
- 无法实现应用内部分界面的录制
- 无法录制扬声器
- 录制桌面的是都鼠标光标闪烁
- 设备的名称如果超过31个字符的话会被截断,而若是将完整的设备名传到参数里则无法进行音频采集,只能将截断的设备名称传进去。
- 录制桌面使用GDI方式的时候如果系统缩放不是100%,在多屏录制的时候录制不全。
这些问题我们一一解决:
前两个问题是无法解决的。
解决方法
安装虚拟设备
第3个和第4个问题可以安装软件实现
我们可以安装一个FFMpeg官方提供的一个软件screen capture recorder
,弊端是这个软件大概40-50m大小。
编译好的下载地址是:
http://sourceforge.net/projects/screencapturer/files/
安装完了之后,在命令行执行:
1 | ffmpeg -list_devices true -f dshow -i dummy |
就会看到多了两个设备
screen-capture-recorder 这个就是桌面捕获设备
virtual-audio-capturer 这个是音频捕获设备(这个录制的不是麦克风的声音,是系统输出的声音)
但是这样软件也太大了,当然我们也有方法:
我们从该软件的目录中复制以下4个DLL自己注册即可,就不用安装该程序了。
注意
注册必须有C++2010环境。
安装C++2010环境的位数要和注册的DLL位数一致,否则无法注册。
注册audio_sniffer.dll
和audio_sniffer-x64.dll
命令行中注册
注意
注册DLL的时候是使用32位的DLL,还是64位的DLL取决于FFmpeg的位数
如果FFmpeg是64位的则注册64位的DLL,如果是32位的只能注册32位的DLL,否则DLL注册上了也不能使用虚拟设备。
而FFmpeg是使用64位还是32位取决于系统的位数,最好和系统保持一致,当然在64位上是可以使用32位的。
这里建议无论是64位还是32位都使用32位的FFmpeg和注册32位的DLL。
打开CMD窗口,执行以下命令:
1 | regsvr32 "D:\Tools\ffmpeg\dll\virtual-audio\audio_sniffer.dll" |
注册screen-capture-recorder.dll
和screen-capture-recorder-x64.dll
注意
必须用管理员身份注册。
打开CMD窗口,执行以下命令:
1 | regsvr32 "D:\Tools\ffmpeg\dll\screen-capture-recorder\screen-capture-recorder.dll" |
解除注册
解除添加/u
即可。
1 | regsvr32 /u "D:\Tools\ffmpeg\dll\virtual-audio\audio_sniffer.dll" |
注意
电脑上的音频设备禁用的话,注册的设备也是不可用的。
获取到的设备名称为
"virtual-audio-capturer" (none)
,正常的应为"virtual-audio-capturer" (audio)
。
代码中注册
1 | using System.Diagnostics; |
推荐无论是64位的系统,还是32位的系统都使用32位的FFmpeg,注册32位的DLL。
1 | Console.WriteLine(@"操作系统为32位系统"); |
如果想判断系统的位数注册对应DLL时要注意FFmpeg也要下载对应的版本。
1 | if (Environment.Is64BitOperatingSystem) |
项目中使用
在项目的根目录添加Libs
文件夹,复制DLL到该文件夹下
属性
=> 生成事件
+> 生成前事件命令行
中添加
1 | xcopy /Y /d $(ProjectDir)\Libs\screen-capture-recorder\* $(TargetDir)\ |
虚拟设备验证
所有设备
1 | ffmpeg -f dshow -list_devices true -i dummpy |
视频设备
1 | ffmpeg -f dshow -list_options true -i video="screen-capture-recorder" |
音频设备
1 | ffmpeg -f dshow -list_options true -i audio="virtual-audio-capturer" |
使用新版本
最后两个问题使用FFmpeg新版本即可,我这里使用的是6.0版本。
安装依赖
Nuget添加依赖
1 | Install-Package NAudio.Core -Version 2.1.0 |
其中
NAudio.Wasapi
的作用:
- 用来获取默认麦克风设备。
- 混音的时候获取扬声器的声音大小进行混音。
或者
这个版本内部没有分离,安装这一个即可。
1 | Install-Package NAudio -Version 1.9.0 |
添加引用
System.Drawing
常用的命令
查看音频和视频设备列表
1 | ffmpeg -f dshow -list_devices true -i dummpy |
查看Dshow库支持参数
1 | ffmpeg -h demuxer=dshow |
视频源
获取视频源支持的分辨率
1 | ffmpeg -f dshow -list_options true -i video="screen-capture-recorder" |
音频源
麦克风
1 | ffmpeg -f dshow -list_options true -i audio="麦克风 (Realtek(R) Audio)" |
扬声器
1 | ffmpeg -f dshow -list_options true -i audio="virtual-audio-capturer" |
获取默认的麦克风
方式1
1 | public static string GetDefaultMicrophone() |
注意
defaultCaptureDevice.FriendlyName
的值为麦克风 (Realtek(R) Audio)
defaultCaptureDevice.DeviceFriendlyName
的值为Realtek(R) Audio
我们要用
defaultCaptureDevice.FriendlyName
获取的值才和FFmpeg获取的一样。
方式2
1 | /// <summary> |
音频录制测试
麦克风
1 | ffmpeg -f dshow -i audio="麦克风 (Realtek(R) Audio)" -t 10 -y "C:\Users\Administrator\AppData\Local\Temp\____temp.wav" |
扬声器
1 | ffmpeg -f dshow -i audio="virtual-audio-capturer" -t 10 -y "C:\Users\Administrator\AppData\Local\Temp\____temp.wav" |
录制命令
1 | ffmpeg -rtbufsize 1000M -thread_queue_size 1024 -f dshow -i audio="virtual-audio-capturer" -f dshow -i audio="麦克风 (Realtek(R) Audio)" -filter_complex amix=inputs=2:duration=longest:dropout_transition=2:weights="0.5 2":normalize=0 -f dshow -video_size 1920x1080 -i video="screen-capture-recorder" -an -c:v libx264 -r 24 -pix_fmt yuv420p -preset:v ultrafast -vf scale=-1:1080 -y "D:\mp4\luping.mp4" |
1 | ffmpeg -rtbufsize 1000M -thread_queue_size 1024 -f dshow -i audio="virtual-audio-capturer" -f dshow -i audio="麦克风 (Realtek(R) Audio)" -filter_complex amix=inputs=2:duration=longest:dropout_transition=2:weights="0.7614819 2":normalize=0 -f dshow -video_size 1920x1080 -i video="screen-capture-recorder" -an -c:v libx264 -r 24 -pix_fmt yuv420p -preset:v ultrafast -vf scale=-1:1080 -y "C:\Users\Administrator\Downloads\Test\20230524095242.mp4" |
音频
1 | Install-Package NAudio.Wasapi -Version 2.1.0 |
默认的麦克风和扬声器
1 | var defaultCaptureDevice = WasapiCapture.GetDefaultCaptureDevice(); |
获取扬声器的声音大小
1 | /// <summary> |
这个方法主要用于麦克风和扬声器混音时,设置混音比。因为默认是用相当于100%的扬声器音量。
判断麦克风是否可用
要想准确判断麦克风是否可用要满足一下三个条件
- 有激活的麦克风设备
- 录制麦克风生成了音频文件
- 音频文件大小要大于0
这三个条件缺一不可
使用FFmpeg判断(推荐)
本来是推荐下面的方式的,但是下面的方式有个问题
在Win7系统上,FFmpeg有问题,获取到的音频设备的名称过长的话就会被截取,而NAudio获取到的名称是完整的,导致传入完整的设备名称进行录制的时候,反而ffmpwg找不到设备,必须传被截取后的名称,所以稳妥的方式就是使用ffmpeg获取设备名称。
示例
1 | /// <summary> |
使用NAudio判断
这种方式相对于FFmpeg的方式,更加的快速,但是不推荐,最好还是使用FFmpeg录制,就用FFmpeg检测。
1 | public static bool IsMicrophoneGood() |
录制工具类
录制
1 | namespace Z.Utils.Record |
暂停和恢复的实现
FFmpeg能实现录制和停止,但是是不支持暂停和恢复的,但是我们可以扩展Process的方法来实现暂停和恢复功能。
1 | using System; |
生成缩略图
1 | /// <summary> |
获取视频时长
1 | /// <summary> |
获取视频信息中有一行
1 | Duration: 00:00:08.00, start: 0.000000, bitrate: 648 kb/s |
从中截取时长
打开系统声音设置
1 | Process.Start("mmsys.cpl"); |
调用本地播放
1 | Process pro = new Process |
环境设置
为了保证录制正常,必须保证FFmpeg安装并设置环境变量。
项目下的ffmpeg的路径
1 | string ffmpegLocation = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe"); |
判断FFmpeg是否安装
这种方式不推荐使用,添加环境变量不能立即生效
1 | /// <summary> |
推荐方式
1 | /// <summary> |
下载FFmpeg
https://www.psvmc.cn/article/2020-02-04-wpf-start-11-file-download.html
设置环境变量
1 | namespace Z.Utils.Record |
结束ffmpeg进程
C#结束ffmpeg进程时,如果我们的程序是32位,而ffmpeg是64位的,我们直接用C#提供的进程类结束是不成功的,因为32位程序无法读取64位进程。
所以这里使用命令行来执行,但是命令行执行还未找到结束指定位置启动的ffmpeg进程的方式。
下面这种方式会结束所有的ffmpeg进程,不推荐在项目中使用,可能会杀掉其他程序的进程。
1 | private void KillFfmpeg() |
实际执行的命令为
1 | taskkill /F /IM ffmpeg.exe |