zoukankan      html  css  js  c++  java
  • 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-难点:视频旋转核心代码(已更新为方法8)

     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-难点:录屏核心代码(这部分代码视频格式可以自行调整,颜色代码原理已经理解。)--已更新为方法10

     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         }

    7-放大缩小(根据屏幕大小范围随意拉伸缩小)  核心代码如下:

    当你有摄像头长跟宽不一样的时候,旋转-缩小-放大然后根据给定的边缘坐标是一个非常头疼的事情,单单这个问题就使我加班到凌晨4点了,不过最终还是解决了;

      1   void resizer_Resize(object sender, ControlResizeEventArgs e)
      2         {
      3             if (!this.RectangleU.IsMouseCaptured) return;
      4             if (AnAngle == 180 || AnAngle == 360)
      5             {
      6                 #region --竖直拉伸--
      7                 double Image_xx = 0;
      8                 double Image_yy = 0;
      9                 double point_xx = 0;
     10                 double point_yy = 0;
     11                 double point_center = Math.Abs(this.MainGrid.Width / 2 - this.MainGrid.Height / 2);//当前中心点值
     12                 double actual_center = Math.Abs(this.videoPlayer.MinWidth / 2 - this.videoPlayer.MinHeight / 2);//实际中心点,用于比较初始值
     13 
     14                 if (Math.Abs(Image_PointX) == 0)
     15                 {
     16                     point_xx = -25;//初始化原点未动
     17                 }
     18                 else
     19                 {
     20                     //拖动到其他位置时偏移量(必须是固定值)
     21                     if (Image_PointX < -25)
     22                     {
     23                         point_xx = -25;
     24                     }
     25                     else
     26                     {
     27                         point_xx = Image_PointX;
     28                     }
     29                 }
     30 
     31                 if (Math.Abs(Image_PointY) == 0)
     32                 {
     33                     point_yy = -25;//初始化原点未动
     34                 }
     35                 else
     36                 {
     37                     //拖动到其他位置时偏移量(必须是固定值)
     38                     if (Image_PointY < -25)
     39                     {
     40                         point_yy = -25;
     41                     }
     42                     else
     43                     {
     44                         point_yy = Image_PointY;
     45                     }
     46 
     47                 }
     48                 if (Math.Abs(point_xx) == 25)
     49                 {
     50                     Image_xx = videoPlayer.ActualHeight;
     51                 }
     52                 else
     53                 {
     54                     Image_xx = videoPlayer.ActualHeight + Math.Abs(Image_PointX) - 25;
     55                 }
     56                 if (Math.Abs(point_yy) == 25)
     57                 {
     58                     Image_yy = videoPlayer.ActualWidth;
     59                 }
     60                 else
     61                 {
     62                     Image_yy = Math.Abs(Image_PointY) + videoPlayer.ActualWidth - 25;
     63                 }
     64 
     65                 //左右拉伸(只能往右拉伸)
     66                 if (e.LeftDirection.HasValue)
     67                 {
     68                     var value = videoPlayer.Height + e.HorizontalChange;
     69                     if (value > videoPlayer.MinHeight)
     70                     {
     71                         videoPlayer.Height = value;
     72                         MainGrid.Height = value;
     73                         if (videoPlayer.ActualHeight < value)
     74                         {
     75                             MainGrid.Height = videoPlayer.ActualHeight;
     76                         }
     77                         if (Image_xx >= RecordingArea.Width)
     78                         {
     79                             MainGrid.Height = videoPlayer.ActualHeight;
     80                             videoPlayer.Height = videoPlayer.ActualHeight;
     81                         }
     82                     }
     83                 }
     84                 //上下拉伸(只能往上拉伸)
     85                 if (e.TopDirection.HasValue)
     86                 {
     87                     var value = videoPlayer.Width + e.VerticalChange;
     88                     if (value > videoPlayer.MinWidth)
     89                     {
     90                         videoPlayer.Width = value;
     91                         MainGrid.Width = value;
     92                         if (videoPlayer.ActualWidth < value)
     93                         {
     94                             MainGrid.Width = videoPlayer.ActualWidth;
     95                         }
     96 
     97                         if (Image_yy >= RecordingArea.Height)
     98                         {
     99                             MainGrid.Width = videoPlayer.ActualWidth;
    100                             videoPlayer.Width = videoPlayer.ActualWidth;
    101                         }
    102 
    103                     }
    104                 }
    105 
    106                 #region 调整位置
    107 
    108                 Matrix m = MainGrid.RenderTransform.Value;
    109 
    110 
    111                 //初始值(-25,-25)-->(x,y)
    112                 if ((Image_xx >= RecordingArea.Width) || Image_yy >= RecordingArea.Height)
    113                 {
    114 
    115                 }
    116                 else
    117                 {
    118                     if (point_center >= actual_center)
    119                     {
    120                         // (point_center - actual_center)为x-y轴偏移量
    121                         //point_xx--point_yy为当前x,y轴坐标
    122                         m.OffsetX = point_xx - (point_center - actual_center);
    123                         m.OffsetY = point_yy - (point_center - actual_center);
    124 
    125                     }
    126                 }
    127                 MainGrid.RenderTransform = new MatrixTransform(m);//重新定位
    128 
    129                 #endregion
    130 
    131 
    132 
    133                 #endregion
    134             }
    135             else
    136             {
    137                 #region --正常拉伸--
    138                 //左右拉伸(只能往右拉伸)
    139                 if (e.LeftDirection.HasValue)
    140                 {
    141                     var value = videoPlayer.Width + e.HorizontalChange;
    142                     if (value > videoPlayer.MinWidth)
    143                     {
    144                         videoPlayer.Width = value;
    145                         MainGrid.Width = value;
    146                         if (videoPlayer.ActualWidth < value)
    147                         {
    148                             MainGrid.Width = videoPlayer.ActualWidth;
    149                         }
    150                         if (Image_PointX + videoPlayer.ActualWidth >= RecordingArea.Width)
    151                         {
    152                             MainGrid.Width = videoPlayer.ActualWidth;
    153                             videoPlayer.Width = videoPlayer.ActualWidth;
    154                         }
    155                     }
    156                 }
    157                 //上下拉伸(只能往上拉伸)
    158                 if (e.TopDirection.HasValue)
    159                 {
    160                     var value = videoPlayer.Height + e.VerticalChange;
    161                     if (value > videoPlayer.MinHeight)
    162                     {
    163                         videoPlayer.Height = value;
    164                         MainGrid.Height = value;
    165                         if (videoPlayer.ActualHeight < value)
    166                         {
    167                             MainGrid.Height = videoPlayer.ActualHeight;
    168                         }
    169 
    170                         if (Math.Abs(Image_PointY) + videoPlayer.ActualHeight >= RecordingArea.Height)
    171                         {
    172                             MainGrid.Height = videoPlayer.ActualHeight;
    173                             videoPlayer.Height = videoPlayer.ActualHeight;
    174                         }
    175 
    176                     }
    177                 }
    178                 #endregion
    179             }
    180         }
    放大缩小-分长宽不一致情况

    8-旋转,核心代码如下:

      1        private void RotateCamera_bt(object sender, RoutedEventArgs e)
      2         {
      3             if (MainGrid.ActualWidth > SystemParameters.PrimaryScreenHeight)
      4             {
      5                 return;
      6             }
      7             if (AnAngle > 360 || AnAngle == 0)
      8             {
      9                 AnAngle = 90;
     10             }
     11 
     12             TransformGroup transformGroup = new TransformGroup();
     13             RotateTransform rotateTransform = new RotateTransform(AnAngle);
     14             transformGroup.Children.Add(rotateTransform);
     15             MainGrid.RenderTransform = transformGroup;
     16             #region 特殊四个角反转需要变换长跟宽
     17             //重新调整坐标坐标位置
     18             Matrix m = MainGrid.RenderTransform.Value;
     19             //求出中心点坐标
     20             double point_xx = (this.MainGrid.ActualWidth) / 2 - (this.MainGrid.ActualHeight) / 2;
     21             // Image_PointX,Image_Point为当前坐标
     22             if (AnAngle == 90 || AnAngle == 270)
     23             {
     24                 if (AnAngle == 270)
     25                 {
     26                     RectangleU.VerticalAlignment = VerticalAlignment.Bottom;
     27                     RectangleU.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
     28                     RectangleU.BorderThickness = new Thickness(0, 0, 8, 8);
     29                     RectangleU.CornerRadius = new CornerRadius(0, 0, 1, 0);
     30 
     31                 }
     32                 else
     33                 {
     34                     RectangleU.VerticalAlignment = VerticalAlignment.Top;
     35                     RectangleU.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
     36                     RectangleU.BorderThickness = new Thickness(8, 8, 0, 0);
     37                     RectangleU.CornerRadius = new CornerRadius(1, 0, 0, 0);
     38 
     39                 }
     40                 if (!IschangeAngle)
     41                 {
     42                     if (Image_PointX <= -point_xx)
     43                     {
     44                         m.OffsetX = -point_xx;
     45                     }
     46                     else
     47                     {
     48                         m.OffsetX = Image_PointX - point_xx;
     49                     }
     50                     if (Image_PointY >= -point_xx)
     51                     {
     52                         m.OffsetY = -point_xx;
     53                     }
     54                     else
     55                     {
     56                         m.OffsetY = Image_PointY + point_xx;
     57                     }
     58 
     59                     if (m.OffsetX >= this.RecordingArea.Width - this.videoPlayer.Width - point_xx)
     60                     {
     61                         m.OffsetX = m.OffsetX + point_xx * 2;
     62 
     63                     }
     64                     if (m.OffsetY >= -point_xx)
     65                     {
     66                         m.OffsetY = -point_xx;
     67                     }
     68                 }
     69                 else
     70                 {
     71                     //旋转为竖直拉到某个坐标时触发
     72                     if (Image_PointX <= -point_xx)
     73                     {
     74                         m.OffsetX = -point_xx;
     75                     }
     76                     else
     77                     {
     78                         m.OffsetX = Image_PointX;
     79                     }
     80                     if (Image_PointY >= point_xx)
     81                     {
     82                         m.OffsetY = -point_xx;
     83                     }
     84                     else
     85                     {
     86                         m.OffsetY = Image_PointY;
     87                     }
     88                 }
     89 
     90                 if (this.MainGrid.Width >= this.RecordingArea.Height)
     91                 {
     92                     //触发
     93                     //相对于屏幕的x,y轴不变
     94                     m.OffsetX = -point_xx;
     95                     m.OffsetY = -point_xx;
     96 
     97 
     98                 }
     99 
    100             }
    101             else
    102             {
    103                 if (AnAngle == 180)
    104                 {
    105                     RectangleU.VerticalAlignment = VerticalAlignment.Bottom;
    106                     RectangleU.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
    107                     RectangleU.BorderThickness = new Thickness(8, 0, 0, 8);
    108                     RectangleU.CornerRadius = new CornerRadius(0, 0, 0, 1);
    109 
    110                 }
    111                 else
    112                 {
    113                     RectangleU.VerticalAlignment = VerticalAlignment.Top;
    114                     RectangleU.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
    115                     RectangleU.BorderThickness = new Thickness(0, 8, 8, 0);
    116                     RectangleU.CornerRadius = new CornerRadius(0, 1, 0, 0);
    117 
    118                 }
    119                 if (IschangeAngle)
    120                 {
    121                     if (this.MainGrid.Width >= this.RecordingArea.Height)
    122                     {
    123                         Image_PointX = 0;
    124                     }
    125                     else
    126                     {
    127                         if (Image_PointX + this.videoPlayer.Width > this.RecordingArea.Width)
    128                         {
    129                             m.OffsetX = Image_PointX - point_xx;
    130                         }
    131                         else
    132                         {
    133                             m.OffsetX = Image_PointX + point_xx;
    134                         }
    135                     }
    136                     //旋转为竖直拉到某个坐标时触发
    137                     if (Image_PointY >= -point_xx)
    138                     {
    139                         m.OffsetY = 0;
    140                     }
    141                     else
    142                     {
    143                         m.OffsetY = Image_PointY - point_xx;
    144                     }
    145 
    146                 }
    147                 else
    148                 {
    149 
    150                     if (this.MainGrid.Width >= this.RecordingArea.Width)
    151                     {
    152                         m.OffsetX = 0;
    153                         m.OffsetY = 0;
    154                     }
    155                     else
    156                     {
    157                         //正常情况
    158                         if (Image_PointX <= 0)
    159                         {
    160                             m.OffsetX = 0;
    161                         }
    162                         else
    163                         {
    164                             m.OffsetX = Image_PointX;
    165                         }
    166                         if (Image_PointY >= 0)
    167                         {
    168                             m.OffsetY = 0;
    169                         }
    170                         else
    171                         {
    172                             m.OffsetY = Image_PointY;
    173                         }
    174                     }
    175                 }
    176             }
    177             //IschangeAngle = false;
    178             //更换坐标位置
    179             MainGrid.RenderTransform = new MatrixTransform(m);
    180 
    181 
    182             var x = Math.Min(this.startPosition.X, this.endPosition.X);
    183             var y = Math.Min(this.startPosition.Y, this.endPosition.Y);
    184             if (AnAngle == 90 || AnAngle == 270)
    185             {
    186                 if (this.MainGrid.Width >= this.RecordingArea.Height)
    187                 {
    188                     this.relativeRecordingArea = new Rect(x, y, this.MainGrid.Height, this.MainGrid.Width);
    189                     this.UpdateUI();
    190                 }
    191             }
    192             else
    193             {
    194                 if (this.MainGrid.Width >= this.RecordingArea.Width)
    195                 {
    196                     this.relativeRecordingArea = new Rect(x, y, this.MainGrid.Width, this.MainGrid.Height);
    197                     this.UpdateUI();
    198                 }
    199             }
    200             //UpdatePosition();
    201 
    202             AnAngle += 90;
    203             #endregion
    204         }
    旋转代码-分长宽不一致情况

    9-不同屏幕百分比自适应边框-采用DPIX

    这个稍微简单点:只要获取出每个屏幕差值即可。

     dpiX = graphics.DpiX / 96;//当前屏幕的DPI然后除以正常值96得出的值即为扩展百分比

    10-录屏核心代码:(不采用之前的位图编译,直接通过引用第三方插件)

    通过AForge对FFMPEG进行录屏封装,我们可以轻松的录制想要录制的内容,关于录屏时间上则采用的是异步执行Timer。

      private void video_NewFrame(object sender, NewFrameEventArgs e)
            {
                //if (this.IScreenRecording)
                //{
                this.videoWriter.WriteVideoFrame(e.Frame);
                //异步执行时间
                this.stopWatchLabel.Dispatcher.Invoke(new Action
                       (() => this.stopWatchLabel.Text = string.Format
                           (@"{0}", this.stopWatch.Elapsed.ToString("hh\\:mm\\:ss"))));
                //}
                //else
                //{
                //    stopWatch.Reset();
                //    videoStreamer.Stop();
                //    videoWriter.Close();
                //}
            }

    11-比较重要的一步:任何商用的录屏软件都需要实现播放、暂停、继续功能,这款软件也不例外:

       /// <summary>
            /// 点击之后更换图标并判断是否需要停止or启用
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void PauseOrRecording_Checked(object sender, RoutedEventArgs e)
            {
    
                //暂停计时
                //暂停保存图片
                //暂停保存麦克风      
                if (IScreenRecording)
                {
                    this.stopWatch.Stop();//时间表
                                          //this.videoStreamer.Stop();
                    this.videoStreamer.SignalToStop();
    
                    if (PassMediaMessage.IsrecordingSound)
                    {
                        //暂停
    
                        PassMediaMessage.IsrecordingSound = false;
                        PassMediaMessage.Is_Recording = false;
                    }
                    IScreenRecording = false;
                }
                else
                {
                    if (this.IsMicrophone.IsChecked == true)
                    {
                        PassMediaMessage.IsrecordingSound = true;
                        PassMediaMessage.Is_Recording = true;
                    }
                    //启用(只是暂停并没有真正的释放)
                    this.stopWatch.Start();//时间表
                    this.videoStreamer.Start();
                    IScreenRecording = true;
                }
            }

    12-由于我们软件是面向世界的,所以必须有增加世界12国语言支持,这边就不再详细贴出代码了。

    13-整体效果展示:

      

    工作的事情要做就要做到最好,做到极致,做到无人能及。
  • 相关阅读:
    Android使用文件存储数据
    Android Sudoku第一版
    Android Preference
    Android Sudoku应用挂掉的问题
    Android刷新Dialog
    Android应用增加计时器
    使用Jquery的Ajax实现无刷新更新,修改,删除页面
    鼠标划过用户名时在鼠标右下角显示div展示用户资料
    网页宽高自适应大小
    学会读JQuery等JS插件源码
  • 原文地址:https://www.cnblogs.com/BarryJames/p/6679407.html
Copyright © 2011-2022 走看看