WPF调用ffmpeg实现屏幕录制

作者:WPF开发者 时间:2023-04-23 13:57:00 

WPF 实现调用 ffmpeg 实现屏幕录制

框架使用.NET4

Visual Studio 2022

需要去 ffmpeg[2] 官网下载 Windows 解压进入 ffmpeg-4.1.1-win32-static\bin\ 或者 下载 ffmpeg.exe[3] 拷贝到运行目录下的ffmpeg 文件夹下 DesktopRecord.exe 就可以进行录屏,结束录屏后视频保存在运行程序根目录下。

使用参数命令进行录屏 "-f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 1920x1080 -i desktop -c:v libx264 -preset ultrafast -crf 0 " + DateTime.Now.ToString("yyyyMMddHHmmss") + "_DesktopRecord.mp4"

  • -f gdigrab: 设定视频输入来源为 Windows 桌面画面捕获;

  • -framerate 30: 设置帧率为 30fps

  • -offset_x 0 -offset_y 0: 设置捕获起始坐标为 (0, 0)

  • -video_size 1920x1080: 设置视频分辨率为 1920x1080

  • -i desktop: 指示从桌面捕获视频流;

  • -c:v libx264: 使用 libx264 编码器进行视频压缩;

  • -preset ultrafast: 设定视频压缩速度为最快;

  • -crf 0: 设置视频压缩质量无限制(CRF 为 0 表示最高质量);

  • " + DateTime.Now.ToString("yyyyMMddHHmmss") + "_DesktopRecord.mp4": 指定视频输出文件名为 yyyyMMddHHmmss_DesktopRecord.mp4

实现代码

1)创建 FFmpegHelper.cs 代码如下:

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace DesktopRecord.Helper
{
    public class FFmpegHelper
    {
        #region 模拟控制台信号需要使用的api
        [DllImport("kernel32.dll")]
        static extern bool GenerateConsoleCtrlEvent(int dwCtrlEvent, int dwProcessGroupId);
        [DllImport("kernel32.dll")]
        static extern bool SetConsoleCtrlHandler(IntPtr handlerRoutine, bool add);
        [DllImport("kernel32.dll")]
        static extern bool AttachConsole(int dwProcessId);
        [DllImport("kernel32.dll")]
        static extern bool FreeConsole();
        #endregion
        // ffmpeg进程
        static Process _process;
        // ffmpeg.exe实体文件路径
        static string ffmpegPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ffmpeg.exe");
        /// <summary>
        /// 功能: 开始录制
        /// </summary>
        public static bool Start()
        {
            if(!File.Exists(ffmpegPath))
                return false;
            var processInfo = new ProcessStartInfo
            {
                FileName = ffmpegPath,
                Arguments = "-f gdigrab -framerate 30 -offset_x 0 -offset_y 0 -video_size 1920x1080 -i desktop -c:v libx264 -preset ultrafast -crf 0 " + DateTime.Now.ToString("yyyyMMddHHmmss") + "_DesktopRecord.mp4",
                UseShellExecute = false,
                RedirectStandardInput = true,
                RedirectStandardOutput = true,
                CreateNoWindow = true
            };
            _process = new Process { StartInfo = processInfo };
            _process.Start();
            return true;
        }
        /// <summary>
        /// 功能: 停止录制
        /// </summary>
        public static void Stop()
        {
            if (_process == null) return;
            AttachConsole(_process.Id);
            SetConsoleCtrlHandler(IntPtr.Zero, true);
            GenerateConsoleCtrlEvent(0, 0);
            FreeConsole();
            _process.StandardInput.Write("q");
            if (!_process.WaitForExit(10000))
            {
                _process.Kill();
            }
        }
    }
}

2)创建 MainWindow.xaml 代码如下:

<wd:Window
    x:Class="DesktopRecord.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:DesktopRecord.ViewModel"
    xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers"
    Title="屏幕录制"
    Width="525"
    Height="200"
    Icon="/screen.ico"
    ResizeMode="CanMinimize"
    WindowStartupLocation="CenterScreen"
    mc:Ignorable="d">
    <wd:Window.DataContext>
        <vm:MainVM />
    </wd:Window.DataContext>
    <Grid>
        <TabControl>
            <TabItem Header="ffmpeg 录制">
                <StackPanel
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"
                    Orientation="Horizontal">
                    <Button
                        Margin="0,0,5,0"
                        Command="{Binding MyStart}"
                        Content="{Binding MyTime}"
                        Style="{StaticResource WD.SuccessPrimaryButton}" />
                    <Button
                        Margin="5,0,0,0"
                        Command="{Binding MyStop}"
                        Content="停止录制"
                        Style="{StaticResource WD.DangerPrimaryButton}" />
                </StackPanel>
            </TabItem>
        </TabControl>
    </Grid>
</wd:Window>

3)创建 MainVM.cs 代码如下:

using DesktopRecord.Helper;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Threading;
using WPFDevelopers.Controls;
using WPFDevelopers.Helpers;
namespace DesktopRecord.ViewModel
{
    public class MainVM : ViewModelBase
    {
        private DispatcherTimer tm = new DispatcherTimer();
        public int currentCount = 0;
        private string myTime = "开始录制";
        public string MyTime
        {
            get { return myTime; }
            set
            {
                myTime = value;
                NotifyPropertyChange("MyTime");
            }
        }
        private bool isStart = true;
        public bool IsStart
        {
            get { return isStart; }
            set
            {
                isStart = value;
                NotifyPropertyChange("IsStart");
            }
        }
        private bool _isShow;
        public bool IsShow
        {
            get { return _isShow; }
            set
            {
                _isShow = value;
                NotifyPropertyChange("IsShow");
            }
        }
        private ICommand myStart;
        public ICommand MyStart
        {
            get
            {
                return myStart ?? (myStart = new RelayCommand(p =>
                {
                    App.Current.MainWindow.WindowState = System.Windows.WindowState.Minimized;
                    if (!FFmpegHelper.Start())
                    {
                        App.Current.MainWindow.WindowState = System.Windows.WindowState.Normal;
                        MessageBox.Show("未找到 【ffmpeg.exe】,请下载", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
                        return;
                    }
                    tm.Tick += tm_Tick;
                    tm.Interval = TimeSpan.FromSeconds(1);
                    tm.Start();
                    IsStart = false;
               }, a =>
                {
                return IsStart;
                }));
            }
        }
        private void tm_Tick(object sender, EventArgs e)
        {
            currentCount++;
            MyTime = "录制中(" + currentCount + "s)";
        }
        /// <summary>
        /// 获取或设置
        /// </summary>
        private ICommand myStop;
        /// <summary>
        /// 获取或设置
        /// </summary>
        public ICommand MyStop
        {
            get
            {
                return myStop ?? (myStop = new RelayCommand(p =>
                           {
                               var task = new Task(() =>
                               {
                                   FFmpegHelper.Stop();
                                   MyTime = "开始录制";
                                   tm.Stop();
                                   currentCount = 0;
                                   IsShow = true;
                               });
                               task.ContinueWith(previousTask =>
                               {
                                   IsShow = false;
                                   IsStart = true;
                                   Process.Start(AppDomain.CurrentDomain.BaseDirectory);
                               }, TaskScheduler.FromCurrentSynchronizationContext());
                               task.Start();
                           }, a =>
            {
                return !IsStart;
            }));
            }
        }

效果图

WPF调用ffmpeg实现屏幕录制

来源:https://mp.weixin.qq.com/s/tPj0fUmCT_UiDYu2_35UkA

标签:WPF,ffmpeg,屏幕,录制
0
投稿

猜你喜欢

  • Java中JMM与volatile关键字的学习

    2022-03-24 00:12:00
  • android自定义View实现圆环颜色选择器

    2023-11-07 19:16:02
  • Java中重定向输出流实现用文件记录程序日志

    2021-12-28 20:57:13
  • 详解c# 委托链

    2021-10-06 23:17:59
  • 基于JavaMail API收发邮件的方法

    2022-03-10 09:34:24
  • Java聊天室之实现运行服务器与等待客户端连接

    2023-11-23 08:16:17
  • C#实现redis读写的方法

    2023-07-13 16:21:35
  • Feign远程调用Multipartfile参数处理

    2022-09-22 02:46:24
  • Android 将view 转换为Bitmap出现空指针问题解决办法

    2022-02-12 02:17:23
  • spring拓展之如何定义自己的namespace

    2022-01-12 05:13:33
  • 从最基本的Java工程搭建SpringMVC+SpringDataJPA+Hibernate

    2023-05-31 20:37:20
  • Springboot通过谷歌Kaptcha 组件生成图形验证码功能

    2021-07-24 23:42:47
  • Java算法实现调整数组顺序使奇数位于偶数之前的讲解

    2022-01-23 22:41:19
  • 浅谈Android应用安全防护和逆向分析之apk反编译

    2022-07-08 01:15:21
  • Java反转数组输出实例代码

    2023-09-04 22:18:48
  • Java经典面试题最全汇总208道(四)

    2023-11-08 23:59:26
  • Android中实现GPS定位的简单例子

    2021-11-24 21:01:25
  • Spring实现一个简单的SpringIOC容器

    2023-02-06 21:03:43
  • Android编程实现的短信编辑器功能示例

    2022-09-08 12:58:44
  • Android编程实现画板功能的方法总结【附源码下载】

    2023-08-05 10:45:07
  • asp之家 软件编程 m.aspxhome.com