WPF 录屏软件研发心得及思路分享

最近由于工程需要开始研发基于Windows的自动录屏软件,很多细节很多功能需要处理,毕竟一个完美的录屏软件不是你随随便便就可以写出来的。首先参考了大部分的录屏软件,在研发的过程中遇到了很多的问题;比如-视频加载、麦克风加载、麦克风音量调节、视频播放进度控、视频音量控制、等等很多细节部分都需要好好规划才能开始做。录屏采用的是视频帧的思维逻辑进行编写的。

目前已经基本上成型,基于WPF采用了Model - View框架进行动态加载,每个线程与线程之间采用Async异步执行,并使用线程等待;录屏基本功能包含了(展示历史录屏记录、删除、录屏、视频编码、视频播放及删除、麦克风调用(音量调节-跟随系统)、加载视频(拖拉-旋转)、系统遮罩 等);编码的核心是采用FFMPEG(这个工具真的非常强大);

这边提供几个核心代码仅供参考:

1-难点:系统遮罩核心方法(使用Windows API):

 1         /// <summary>
 2         /// 视图模型属性改变
 3         /// </summary>
 4         /// <param name="sender">
 5         /// The sender.
 6         /// </param>
 7         /// <param name="propertyChangedEventArgs">
 8         /// 属性改变事件参数
 9         /// </param>
10         private void ViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
11         {
12             if (propertyChangedEventArgs.PropertyName == "IsRecording")
13             {
14                 this.Locked = this.ViewModel.IsRecording;
15                 if (this.ViewModel.IsRecording)
16                 {
17                    var hwnd = new WindowInteropHelper(this).Handle;
18                     NativeWindowHelper.SetWindowExTransparent(hwnd);
19                 }
20             }
21
22             if (propertyChangedEventArgs.PropertyName == "IsFullScreen")
23             {
24                 this.IsFullScreen = this.ViewModel.IsFullScreen;
25             }
26         }

改变属性的时候触发

 1         #region Constants
 2
 3         /// <summary>
 4         ///     The gw l_ exstyle.
 5         /// </summary>
 6         [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:FieldNamesMustNotContainUnderscore",
 7             Justification = "Reviewed. Suppression is OK here.")]
 8         private const int GWL_EXSTYLE = -20;
 9
10         /// <summary>
11         ///     The w s_ e x_ transparent.
12         /// </summary>
13         [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:FieldNamesMustNotContainUnderscore",
14             Justification = "Reviewed. Suppression is OK here.")]
15         private const int WS_EX_TRANSPARENT = 0x00000020;
16
17
18
19
20         #endregion
21
22         #region Public Methods and Operators
23
24         /// <summary>
25         /// 窗口前置透明设置命令
26         /// </summary>
27         /// <param name="hwnd">
28         /// The hwnd.
29         /// </param>
30         public static void SetWindowExTransparent(IntPtr hwnd)
31         {
32             var extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
33             SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
34         }
35
36         #endregion
37
38         #region Methods
39
40         /// <summary>
41         /// The get window long.
42         /// </summary>
43         /// <param name="hwnd">
44         /// The hwnd.
45         /// </param>
46         /// <param name="index">
47         /// The index.
48         /// </param>
49         /// <returns>
50         /// The <see cref="int"/>.
51         /// </returns>
52         [DllImport("user32.dll")]
53         private static extern int GetWindowLong(IntPtr hwnd, int index);
54
55         /// <summary>
56         /// The set window long.
57         /// </summary>
58         /// <param name="hwnd">
59         /// The hwnd.
60         /// </param>
61         /// <param name="index">
62         /// The index.
63         /// </param>
64         /// <param name="newStyle">
65         /// The new style.
66         /// </param>
67         /// <returns>
68         /// The <see cref="int"/>.
69         /// </returns>
70         [DllImport("user32.dll")]
71         private static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
72
73         #endregion

API方法

2-难点:麦克风获取及控制

<Slider x:Name="volumeSlider" Grid.Column="7" Grid.ColumnSpan="3" Grid.Row="1" Width="100" Height="20" Minimum="0" Maximum="100" Value="100" VerticalAlignment="Center" />
 1  //定义一个获取之前拉动时候的value值,然后跟当前的value对比,选择触发
 2         private bool isUserChangeVolume = true;
 3         private VolumeControl volumeControl;
 4         //private DispatcherTimer volumeControlTimer;
 5
 6         /// <summary>
 7         /// 加载拖动条的事件
 8         /// </summary>
 9         /// <param name="sender"></param>
10         /// <param name="e"></param>
11         private void volumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
12         {
13             if (isUserChangeVolume)
14             {
15                 volumeControl.MasterVolume = volumeSlider.Value;
16             }
17         }
18
19         private void InitializeAudioControl()
20         {
21             volumeControl = VolumeControl.Instance;
22             volumeControl.OnAudioNotification += volumeControl_OnAudioNotification;
23             volumeControl_OnAudioNotification(null, new AudioNotificationEventArgs() { MasterVolume = volumeControl.MasterVolume });
24
25             //volumeControlTimer = new DispatcherTimer();
26             //volumeControlTimer.Interval = TimeSpan.FromTicks(150);
27             //volumeControlTimer.Tick += volumeControlTimer_Tick;
28         }
29
30         void volumeControl_OnAudioNotification(object sender, AudioNotificationEventArgs e)
31         {
32             this.isUserChangeVolume = false;
33             try
34             {
35                 this.Dispatcher.Invoke(new Action(() => { volumeSlider.Value = e.MasterVolume; }));
36             }
37             catch { }
38             this.isUserChangeVolume = true;
39         }
40
41         void volumeControlTimer_Tick(object sender, EventArgs e)
42         {
43             //获取系统主声道、左声道、右声道音量值
44             //double[] information = volumeControl.AudioMeterInformation;
45             //mMasterPBar.Value = information[0];
46             //mLeftPBar.Value = information[1];
47             //mRightPBar.Value = information[2];
48         }

3-难点:系统遮罩(其实也不能算难点,这个是API调用的时候颜色控制);

4-难点:视频旋转核心代码

 1  /// <summary>
 2         /// 旋转视频
 3         /// </summary>
 4         /// <param name="sender"></param>
 5         /// <param name="e"></param>
 6         private void RotateCamera_bt(object sender, RoutedEventArgs e)
 7         {
 8             if (AnAngle > 360 || AnAngle == 0)
 9             {
10                 AnAngle = 90;
11             }
12             TransformGroup transformGroup = new TransformGroup();
13
14             ScaleTransform scaleTransform = new ScaleTransform();
15             scaleTransform.ScaleX = -1;
16             transformGroup.Children.Add(scaleTransform);
17
18             RotateTransform rotateTransform = new RotateTransform(AnAngle);
19             transformGroup.Children.Add(rotateTransform);
20             videoPlayer.RenderTransform = transformGroup;
21             AnAngle += 90;
22         }

旋转视频代码

5-难点:录屏核心代码(这部分代码视频格式可以自行调整,颜色代码原理已经理解。)

 1  /// <summary>
 2         ///     Starts the recording.
 3         /// </summary>
 4         public void StartRecording()
 5         {
 6             this.notifyIcon.HideBalloonTip();
 7             this.IsRecording = true;
 8
 9
10             var fileName = string.Format("Recording {0}.mp4", DateTime.Now.ToString("yy-MM-dd HH-mm-ss"));
11             var outputFilePath = Path.Combine(this.settings.StoragePath, fileName);
12             this.fileViewModel = new ScreenGunFileViewModel(outputFilePath, RecordingStage.DoingNothing);
13
14             var opts = new ScreenRecorderOptions(this.RecordingRegion)
15             {
16                 DeleteMaterialWhenDone = true,
17                 OutputFilePath = outputFilePath,
18                 RecordMicrophone = this.UseMicrophone,
19                 AudioRecordingDeviceNumber = this.settings.RecordingDeviceNumber
20             };
21
22             var progress = new Progress<RecorderState>(state => this.fileViewModel.RecordingStage = state.Stage);
23             this.recorder.Start(opts, progress);
24         }

录屏代码

6-难点:屏幕画框代码(采集X,Y坐标及遮幕的宽,高)

 1  /// <summary>
 2         ///     设置初始区域
 3         /// </summary>
 4         private void SetupInitialRegion()
 5         {
 6             var cursorPos = System.Windows.Forms.Cursor.Position;
 7             foreach (var screen in Screen.AllScreens)
 8             {
 9                 if (screen.Bounds.Contains(cursorPos) == false)
10                 {
11                     continue;
12                 }
13
14                 var regionWidth = (double)screen.Bounds.Width / 2;
15                 var regionHeight = (double)screen.Bounds.Height / 2;
16                 double x = ((double)screen.Bounds.Width / 2) - (regionWidth / 2);
17                 double y = ((double)screen.Bounds.Height / 2) - (regionHeight / 2);
18                 x -= this.virtualScreen.X - screen.Bounds.X;
19                 y -= this.virtualScreen.Y - screen.Bounds.Y;
20
21                 this.startPosition = new Point(x, y);
22                 this.endPosition = new Point(x + regionWidth, y + regionHeight);
23                 this.UpdatePosition();
24                 break;
25             }
26         }

以上是这几天研究的成果,目前还在进一步研究中,效果图如下:

时间: 2024-10-23 01:24:27

WPF 录屏软件研发心得及思路分享的相关文章

Android录屏应用开发研究

1截屏接口 在Android5.0之前如果希望截图屏幕,是需要获取系统root权限的.但在Android5.0之后Android开放了新的接口android.media.projection,开发者使用该接口,第三方应用程序无需再获取系统root权限也可以直接进行屏幕截图操作了.查询其官方api可知,该接口主要用来"屏幕截图"操作和"音频录制"操作,这里只讨论用于屏幕截图的功能.由于使用了媒体的映射技术手段,故截取的屏幕并不是真正的设备屏幕,而是截取的通过映射出来的

ffmpeg,rtmpdump和nginx rtmp实现录屏,直播和录制

公司最近在做视频直播的项目,我这里分配到对直播的视频进行录制,录制的方式是通过rtmpdump对rtmp的视频流进行录制 前置的知识 ffmpeg: 用于实现把录屏工具发出的视频和音频流,转换成我们需要的格式,然后发送到rtmp中转服务器上. rtmpdump: 用于实现视频的录制,从rtmp的中转服务器接受到视频流,并把视频流保存成flv文件 nginx-rtmp-module: 用户rtmp中转服务,虽然他可以做很多功能,但是我这里只是使用了这一个 screen capture: windo

android 调用 screenrecord 实现录屏

首先要说明的是并未实现,本文讲一下自己的思路. adb 使用shell 命令 screenrecord 可录屏. 自己写了个app,通过Process p = Runtime.getRuntime().exec(cmd)的方式调用shell命令,报错: java.lang.SecurityException: Permission Denial: broadcast asks to run as user -2 but is calling from user 0 需要android.permi

【原创】苹果内置录屏SDK-ReplayKit库的使用说明

1 iOS ReplayKit 录屏SDK 说明 (按照苹果官方的说法是App端加入这些苹果的新特性新SDK更容易被苹果推荐 ) ReplayKit是苹果在iOS9上面提供的一个库组件,可以让玩家在游戏中录制游戏视频,并且可以添加语音评论,然后通过社交网络分享出去. 2库的特性说明 要使用ReplayKit需要在工程的Build Phase的Link binary with libraries中加入ReplayKit.framework. 目前这个库只支持真机允许,不支持模拟器. 系统版本如果低

会员管理系统的设计和开发(3)--主界面的设计思路分享

会员管理系统经过一段时间的紧锣密鼓开发,软件终于完成并发布.在这期间,碰到了不少技术难点,并积累了不少开发心得和经验,本篇继续介绍这个开发过程中相关的技术要点,本章主要介绍会员管理里面,列表主界面的一些设计思路分享. 有时候,遵循一些固定的套路做事情,总是很容易,如果每个地方搞一些创新和改进,那么往往需要花费很多时间,但是创新是有积极意义的,虽然可能会遇到困难,但是很值得去做.在Winform的界面设计上,虽然我可以使用代码生成工具生成比较标准的界面了,但是我总是喜欢参考学习,并改进一些界面方面

游戏录屏直播的图文教程(基于云直播平台)

原创教程 ( 转载请注明出处 ) 2017-6-26,今天来做一下是电脑游戏桌面录屏直播的教程,就是把桌面的游戏直播出去,加上话筒做讲解.最终实现在电脑.手机.微信中都可以观看到游戏的直播和讲解画面. 提示:1. 本教程说的是游戏录屏直播的图文教程(基于云直播平台,不是基于自建流媒体直播平台) 2. 若要基于自建的流媒体平台,可以用OBS之类的软件来实现,OBS取流发送到自建平台上,实现直播. STEP1 . 硬件准备及设备连接 场景说明: 1.用户做一场电脑游戏桌面直播,实现PC端.手机端(A

python 自动录屏初步实现

偶尔需要用python实现录屏并导出视频,随便写了一个简单的代码. 大概思路是先每隔一段时间截屏,然后将截屏图片变成视频导出. 1 # -*- coding: cp936 -*- 2 from PIL import ImageGrab 3 import time,os,cv2 4 import numpy as np 5 def releasevideo(): 6 path=os.getcwd()+'\\picture\\' 7 filelist=os.listdir(path) 8 fps=2

win7电脑怎么录屏?

有些时候我们需要进行些录屏操作,那么怎么录制视频呢?其实录制视频还是比较简单的,有一款屏幕录像工具请添加链接描述就足够了,比如说迅捷屏幕录像工具就十分的不错,下面小编便来分享下win7电脑录屏的具体方法给大家,希望对大家能够有所帮助. 电脑录屏软件http://www.xunjieshipin.com/download-luping 一.首先我们下载一款屏幕录像工具,之后根据软件上安装提示进行安装,整个过程大约花费几分钟. 二.当屏幕录像工具安装完成之后,我们打开它,然后根据我们录制的视频对功能

电脑有什么好用的录屏软件?电脑录屏软件

有时候用一款好用的录屏软件可以使我们录制电脑屏幕视频录制的非常顺畅,身心非常的舒服,那么电脑上有什么比较好用的录屏软件呢?小编觉得迅捷屏幕录像工具,下面小编就给大家分析分析,并分享下使用它录制电脑视频的具体方法. 桌面录屏软件http://www.xunjieshipin.com/download-luping 一.电脑什么录屏软件好用?一款好用的录屏软件,首先得保证我们录制下来的视频播放是十分顺畅的,其次就是保证画质是清晰的而又完美,支持多样的视频录制格式. 二.小编这有一款录屏软件就支持三种