• C# wpf使用ffmpeg命令行实现录屏


    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);
    /// 
    /// 枚举录音设备
    /// 
    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);
        }
    }
    
    • 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
    • 27
    • 28
    • 29
    • 30

    获取音频设备名称

    string audio = null;
    //获取音频采集设备名称
    foreach (var i in EnumDevices.AudioInputDevices)
    {
        audio = i;
        break;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    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     
    
    • 1

    启动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()
    
    • 1
    • 2
    • 3
    • 4

    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()));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    二、完整代码

    实现了录屏功能,包括画面和声音的录制,只依赖ffmpeg.exe。

    之后上传


    三、效果预览

    1、录制中

    在这里插入图片描述

    2、录制动态流程

    在这里插入图片描述


    总结

    以上就是今天要讲的内容了,因为使用了命令行所以录屏逻辑不用自己实现,但是要控制ffmpeg子进程还是有不少细节需要处理的,比如进程自动退出、信息反馈、停止录屏、异常提示等。另外一方面在界面上也有需要处理的东西,比如可控的点击穿透、控制窗口置顶等等。总的来说,实现这一一个功能模块还是需要一定的时间和精力,以及一些相关的知识。

  • 相关阅读:
    qt设置tableView中文字颜色(使用自定义model)
    [多媒体] 多媒体封装格式 —— MP4 vs MKV
    6. CSS动画技巧
    【解决】sklearn-LabelEncoder遇到没在编码规则里的新值
    C/C++ 11/14/17 有栈式协同程式的基础框架类库【关于】
    常见DOS命令总结
    电脑重装系统如何在 Win11查看显卡型号信息
    Python之列表操作和内存模型
    抖音小程序没人做了吗?
    Elastic Stack 8.11:引入一种新的强大查询语言 ES|QL
  • 原文地址:https://blog.csdn.net/u013113678/article/details/126109965