1,項目介紹。
實現全屏錄屏、選擇區域錄屏、攝像頭錄像、麥克風錄音、主板音頻錄音、截屏畫板的自由組合。并通過FFmpeg
完成音頻與視頻的合并。
功能界面
畫板畫筆
參考的項目
https://github.com/yangjinming1062/RecordWin
本項目是在此項目的基礎上修復了部分bug,并增加了屏幕區域錄屏,與主板音頻錄音功能。
2,知識點總結
2.1,熱鍵注冊。
在WPF
中進行熱鍵注冊需要添加鉤子,用以監視熱鍵輸入。
public IntPtr winHandle;
private HwndSource hWndSource;
private void Window_Loaded(object sender, RoutedEventArgs e)
{//獲取窗口句柄winHandle = new WindowInteropHelper(this).Handle;//在Win32窗口呈現wpf內容hWndSource = HwndSource.FromHwnd(winHandle);GoToScreenTopMiddle();SetHotKey(true);}private void SetHotKey(bool Add){if (Add){hWndSource.AddHook(MainWindowProc);HotKeyBF = HotKey.GlobalAddAtom($"{SettingHelp.Settings.播放暫停.Item1}-{Enum.GetName(typeof(System.Windows.Forms.Keys), SettingHelp.Settings.播放暫停.Item2)}");HotKeyTZ = HotKey.GlobalAddAtom($"{SettingHelp.Settings.停止關閉.Item1}-{Enum.GetName(typeof(System.Windows.Forms.Keys), SettingHelp.Settings.停止關閉.Item2)}");HotKeyHB = HotKey.GlobalAddAtom($"{SettingHelp.Settings.開關畫筆.Item1}-{Enum.GetName(typeof(System.Windows.Forms.Keys), SettingHelp.Settings.開關畫筆.Item2)}");HotKey.RegisterHotKey(winHandle, HotKeyBF, SettingHelp.Settings.播放暫停.Item1, SettingHelp.Settings.播放暫停.Item2);HotKey.RegisterHotKey(winHandle, HotKeyTZ, SettingHelp.Settings.停止關閉.Item1, SettingHelp.Settings.停止關閉.Item2);HotKey.RegisterHotKey(winHandle, HotKeyHB, SettingHelp.Settings.開關畫筆.Item1, SettingHelp.Settings.開關畫筆.Item2);}else//暫時沒起作用,todo{hWndSource.RemoveHook(MainWindowProc);HotKey.GlobalDeleteAtom((short)HotKeyBF);HotKey.GlobalDeleteAtom((short)HotKeyTZ);HotKey.GlobalDeleteAtom((short)HotKeyHB);HotKey.UnregisterHotKey(winHandle, HotKeyBF);HotKey.UnregisterHotKey(winHandle, HotKeyTZ);HotKey.UnregisterHotKey(winHandle, HotKeyHB);}}private IntPtr MainWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled){switch (msg){case HotKey.WM_HOTKEY:{int sid = wParam.ToInt32();if (Visibility == Visibility.Visible){if (!SettingPop.IsOpen){if (sid == HotKeyBF){if (btBegin.Visibility == Visibility.Visible)btBegin_Click(null, null);elsebtParse_Click(null, null);}else if (sid == HotKeyTZ){if (btStop.Visibility == Visibility.Visible)btStop_Click(null, null);elseBtClose_Click(null, null);}}if (sid == HotKeyHB){btPen.IsChecked = !btPen.IsChecked;OpenDraweWin();}}handled = true;break;}}return IntPtr.Zero;}
外部函數
public class HotKey{/// <summary> /// 如果函數執行成功,返回值不為0。 /// 如果函數執行失敗,返回值為0。要得到擴展錯誤信息,調用GetLastError。.NET方法:Marshal.GetLastWin32Error() /// </summary> /// <param name="hWnd">要定義熱鍵的窗口的句柄</param> /// <param name="id">定義熱鍵ID(不能與其它ID重復) </param> /// <param name="fsModifiers">標識熱鍵是否在按Alt、Ctrl、Shift、Windows等鍵時才會生效</param> /// <param name="vk">定義熱鍵的內容,WinForm中可以使用Keys枚舉轉換, /// WPF中Key枚舉是不正確的,應該使用System.Windows.Forms.Keys枚舉,或者自定義正確的枚舉或int常量</param> [DllImport("user32.dll", SetLastError = true)]public static extern bool RegisterHotKey(IntPtr hWnd, int id, KeyModifiers fsModifiers, int vk);/// <summary> /// 取消注冊熱鍵 /// </summary> /// <param name="hWnd">要取消熱鍵的窗口的句柄</param> /// <param name="id">要取消熱鍵的ID</param> [DllImport("user32.dll", SetLastError = true)]public static extern bool UnregisterHotKey(IntPtr hWnd, int id);/// <summary> /// 向全局原子表添加一個字符串,并返回這個字符串的唯一標識符,成功則返回值為新創建的原子ID,失敗返回0 /// </summary> [DllImport("kernel32", SetLastError = true)]public static extern short GlobalAddAtom(string lpString);[DllImport("kernel32", SetLastError = true)]public static extern short GlobalDeleteAtom(short nAtom);/// <summary> /// 定義了輔助鍵的名稱(將數字轉變為字符以便于記憶,也可去除此枚舉而直接使用數值) /// </summary> [Flags()]public enum KeyModifiers{None = 0,Alt = 1,Ctrl = 2,Shift = 4,WindowsKey = 8}/// <summary> /// 熱鍵的對應的消息ID /// </summary> public const int WM_HOTKEY = 0x312;}
2. 2,兩種透明。
根據實際需要可以定義兩種透明,一種是真透明Transparent
,一種是假透明#01000000
<Color x:Key="FakeTransparentColor" >#01000000</Color><Color x:Key="TrueTransparentColor" >Transparent</Color>
Background = Application.Current.Resources[enable ? "FakeTransparent" : "TrueTransparent"] as Brush;
在窗口定義為接受透明時:AllowsTransparency="True"
,采用真透明背景的窗體A,覆蓋在應用B上時,應用B的控件可透過窗體A被操作。采用假透明背景的窗體A,覆蓋在應用B上時,應用B的控件不能透過窗體A被操作。
2. 3,音視頻合并。
音視頻的合并一般以命令的形式調用軟件FFmpeg
完成。
下載FFmpeg軟件
常用語法:
-
?直接合并(視頻流復制+音頻轉碼)
若需保持視頻無損且兼容MP4容器,建議將WAV轉碼為AAC:
ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -strict experimental output.mp4
? 參數說明:
-
-c:v copy
:復制視頻流不重新編碼 -
-c:a aac
:將WAV音頻轉碼為MP4支持的AAC格式 -
-strict experimental
:早期版本需此參數支持AAC?
- ?強制替換原視頻音頻軌道?
若原視頻已含音頻需替換,可指定映射關系:
ffmpeg -i video.mp4 -i audio.wav -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 output.mp4
參數說明
-map 0:v:0
:選擇第一個輸入文件(video.mp4)的視頻流-map 1:a:0
:選擇第二個輸入文件(audio.wav)的音頻流?
- ?無損合并(需視頻無音頻)
若視頻本身無音頻軌道,可直接復制流:
ffmpeg -i video.mp4 -i audio.wav -c copy output.mkv
注意:需改用MKV容器以支持PCM音頻流?。
-
示例:
將視頻1.mp4與音頻1.wav合并為output.mkv
2. 4,自定義動畫。
public class CornerRadiusAnimation : AnimationTimeline{static CornerRadiusAnimation(){FromProperty = DependencyProperty.Register("From", typeof(CornerRadius), typeof(CornerRadius));ToProperty = DependencyProperty.Register("To", typeof(CornerRadius), typeof(CornerRadius));}private bool _fromSetted;private bool _toSetted;public static readonly DependencyProperty FromProperty;public CornerRadius From{get => (CornerRadius)GetValue(FromProperty);set{SetValue(FromProperty, value);_fromSetted = true;}}public static readonly DependencyProperty ToProperty;public CornerRadius To{get => (CornerRadius)GetValue(ToProperty);set{SetValue(ToProperty, value);_toSetted = true;}}public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock){var fromVal = _fromSetted ? (CornerRadius)GetValue(FromProperty) : (CornerRadius)defaultOriginValue;var toVal = _toSetted ? (CornerRadius)GetValue(ToProperty) : (CornerRadius)defaultDestinationValue;if (animationClock.CurrentProgress != null)return new CornerRadius(animationClock.CurrentProgress.Value * (toVal.TopLeft - fromVal.TopLeft) + fromVal.TopLeft,animationClock.CurrentProgress.Value * (toVal.TopRight - fromVal.TopRight) + fromVal.TopRight,animationClock.CurrentProgress.Value * (toVal.BottomRight - fromVal.BottomRight) + fromVal.BottomRight,animationClock.CurrentProgress.Value * (toVal.BottomLeft - fromVal.BottomLeft) + fromVal.BottomLeft);return new CornerRadius();}protected override Freezable CreateInstanceCore() => new CornerRadiusAnimation();public override Type TargetPropertyType => typeof(CornerRadius);}
2.5,注意事項
不同目標框架的.NetFramework
,編譯后的.dll不一定相同,例如使用.NetFramerwork4.6.1
將生成大量系統自帶的.dll
。
如下:面對同一個解決方案
.NetFramerwork4.7
編譯清單。
.NetFramerwork4.6.1
編譯清單
3,項目鏈接
https://download.csdn.net/download/lingxiao16888/91461603