From 944c6c90a06ccf4cf75a1cf36b332dc5a8bfbdd6 Mon Sep 17 00:00:00 2001 From: Mercury Date: Tue, 10 Sep 2024 16:43:10 +0200 Subject: [PATCH] add GPU autodetection for HW accelerated recording and encoding. --- 2dxAutoClip/iidxAutoClip.cs | 100 +++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/2dxAutoClip/iidxAutoClip.cs b/2dxAutoClip/iidxAutoClip.cs index 2698386..2c4c2f4 100644 --- a/2dxAutoClip/iidxAutoClip.cs +++ b/2dxAutoClip/iidxAutoClip.cs @@ -1,15 +1,17 @@ using System.Diagnostics; using System.Net.WebSockets; using System.Text; +using System.Management; using NAudio.CoreAudioApi; using NAudio.Wave; +// ReSharper disable PossibleInvalidCastExceptionInForeachLoop namespace _2dxAutoClip; +#pragma warning disable CA1416 class Program { private static readonly string WebsocketAddress = "localhost"; - private static readonly int WebsocketPort = 10573; private static Process? _ffmpegProcess; private static string _ffmpegFolderPath = GetDefaultVideosFolderPath(); private static WasapiCapture? _waveSource; @@ -20,7 +22,7 @@ class Program private static int _framerate = 60; // Default framerate private static float _crf = 23; // Default CRF value private static string _gameProcessName = "spice64"; // Default game process name - + private static async Task Main(string[] args) { // Load settings from prop.txt @@ -99,11 +101,11 @@ class Program private static async Task TryConnectWebSocket() { const int maxRetries = 5; - int attempt = 0; + var attempt = 0; while (attempt < maxRetries) { Console.WriteLine($"Attempt {attempt + 1} of {maxRetries} to connect..."); - bool success = await ConnectWebSocket(); + var success = await ConnectWebSocket(); if (success) break; attempt++; if (attempt < maxRetries) @@ -120,7 +122,7 @@ class Program private static async Task ConnectWebSocket() { - var tickerUri = new Uri($"ws://{WebsocketAddress}:{WebsocketPort}"); + var tickerUri = new Uri($"ws://{WebsocketAddress}:10573"); var reconnecting = false; var lastMessage = string.Empty; var consecutiveMessageCount = 0; @@ -229,29 +231,77 @@ class Program } private static void StartFfmpegRecording(string songName) +{ + var encoder = GetHardwareEncoder(); + + var date = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"); + _videoFilePath = $"{_ffmpegFolderPath}\\{songName}_{date}.mkv"; + var ffmpegArguments = $"-framerate {_framerate} " + + $"-filter_complex \"ddagrab=framerate={_framerate},hwdownload,format=bgra\" " + + $"{encoder} -crf {_crf} -video_size {_resolution} -movflags +faststart -y \"{_videoFilePath}\""; + _ffmpegProcess = new Process { - var date = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"); - _videoFilePath = $"{_ffmpegFolderPath}\\{songName}_{date}.mkv"; - var ffmpegArguments = $"-framerate {_framerate} " + - $"-filter_complex \"ddagrab=framerate={_framerate},hwdownload,format=bgra\" " + - $"-c:v libx264 -tune zerolatency -crf {_crf} -video_size {_resolution} -movflags +faststart -y \"{_videoFilePath}\""; - _ffmpegProcess = new Process + StartInfo = new ProcessStartInfo { - StartInfo = new ProcessStartInfo - { - FileName = "ffmpeg", - Arguments = ffmpegArguments, - UseShellExecute = false, - RedirectStandardError = true, - CreateNoWindow = true - } - }; - _ffmpegProcess.ErrorDataReceived += (_, args) => Console.WriteLine(args.Data); - _ffmpegProcess.Start(); - _ffmpegProcess.BeginErrorReadLine(); + FileName = "ffmpeg", + Arguments = ffmpegArguments, + UseShellExecute = false, + RedirectStandardError = true, + CreateNoWindow = true + } + }; + _ffmpegProcess.Start(); - Console.WriteLine("FFmpeg recording started."); + Console.WriteLine("FFmpeg recording started."); +} + +private static string GetHardwareEncoder() +{ + var graphicsCard = GetGraphicsCard(); + var encoder = "-c:v libx264"; + + if (graphicsCard.Contains("NVIDIA")) + { + encoder = "-c:v h264_nvenc"; + Console.WriteLine("Using NVIDIA hardware encoding (h264_nvenc)."); } + else if (graphicsCard.Contains("AMD")) + { + encoder = "-c:v h264_amf"; + Console.WriteLine("Using AMD hardware encoding (h264_amf)."); + } + else if (graphicsCard.Contains("INTEL")) + { + encoder = "-c:v h264_qsv"; + Console.WriteLine("Using Intel hardware encoding (h264_qsv)."); + } + else + { + Console.WriteLine("No recognized hardware encoder found, using CPU (libx264)."); + } + + return encoder; +} + +private static string GetGraphicsCard() +{ + var searcher = new ManagementObjectSearcher("SELECT * FROM Win32_DisplayConfiguration"); + var graphicsCard = ""; + + foreach (ManagementObject obj in searcher.Get()) + { + foreach (var prop in obj.Properties) + { + if (prop.Name == "Description" && prop.Value != null) + { + graphicsCard = prop.Value.ToString().ToUpper(); + break; + } + } + } + + return graphicsCard; +} private static void StopRecording(string songName) { @@ -280,7 +330,7 @@ class Program { var combinedOutputFilePath = $"{_ffmpegFolderPath}\\{songName}_combined_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.mp4"; var ffmpegArgs = - $"-y -i \"{videoFilePath}\" -i \"{audioFilePath}\" -c:v copy -c:a aac -strict experimental -shortest \"{combinedOutputFilePath}\""; + $"-y -i \"{videoFilePath}\" -i \"{audioFilePath}\" -c:v copy -c:a aac -strict experimental -shortest -hwaccel_output_format d3d11 \"{combinedOutputFilePath}\""; var processInfo = new ProcessStartInfo {