add GPU autodetection for HW accelerated recording and encoding.

This commit is contained in:
Mercury 2024-09-10 16:43:10 +02:00
parent cc70624b54
commit 944c6c90a0

View file

@ -1,15 +1,17 @@
using System.Diagnostics; using System.Diagnostics;
using System.Net.WebSockets; using System.Net.WebSockets;
using System.Text; using System.Text;
using System.Management;
using NAudio.CoreAudioApi; using NAudio.CoreAudioApi;
using NAudio.Wave; using NAudio.Wave;
// ReSharper disable PossibleInvalidCastExceptionInForeachLoop
namespace _2dxAutoClip; namespace _2dxAutoClip;
#pragma warning disable CA1416
class Program class Program
{ {
private static readonly string WebsocketAddress = "localhost"; private static readonly string WebsocketAddress = "localhost";
private static readonly int WebsocketPort = 10573;
private static Process? _ffmpegProcess; private static Process? _ffmpegProcess;
private static string _ffmpegFolderPath = GetDefaultVideosFolderPath(); private static string _ffmpegFolderPath = GetDefaultVideosFolderPath();
private static WasapiCapture? _waveSource; private static WasapiCapture? _waveSource;
@ -20,7 +22,7 @@ class Program
private static int _framerate = 60; // Default framerate private static int _framerate = 60; // Default framerate
private static float _crf = 23; // Default CRF value private static float _crf = 23; // Default CRF value
private static string _gameProcessName = "spice64"; // Default game process name private static string _gameProcessName = "spice64"; // Default game process name
private static async Task Main(string[] args) private static async Task Main(string[] args)
{ {
// Load settings from prop.txt // Load settings from prop.txt
@ -99,11 +101,11 @@ class Program
private static async Task TryConnectWebSocket() private static async Task TryConnectWebSocket()
{ {
const int maxRetries = 5; const int maxRetries = 5;
int attempt = 0; var attempt = 0;
while (attempt < maxRetries) while (attempt < maxRetries)
{ {
Console.WriteLine($"Attempt {attempt + 1} of {maxRetries} to connect..."); Console.WriteLine($"Attempt {attempt + 1} of {maxRetries} to connect...");
bool success = await ConnectWebSocket(); var success = await ConnectWebSocket();
if (success) break; if (success) break;
attempt++; attempt++;
if (attempt < maxRetries) if (attempt < maxRetries)
@ -120,7 +122,7 @@ class Program
private static async Task<bool> ConnectWebSocket() private static async Task<bool> ConnectWebSocket()
{ {
var tickerUri = new Uri($"ws://{WebsocketAddress}:{WebsocketPort}"); var tickerUri = new Uri($"ws://{WebsocketAddress}:10573");
var reconnecting = false; var reconnecting = false;
var lastMessage = string.Empty; var lastMessage = string.Empty;
var consecutiveMessageCount = 0; var consecutiveMessageCount = 0;
@ -229,29 +231,77 @@ class Program
} }
private static void StartFfmpegRecording(string songName) 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"); StartInfo = new ProcessStartInfo
_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 FileName = "ffmpeg",
{ Arguments = ffmpegArguments,
FileName = "ffmpeg", UseShellExecute = false,
Arguments = ffmpegArguments, RedirectStandardError = true,
UseShellExecute = false, CreateNoWindow = true
RedirectStandardError = true, }
CreateNoWindow = true };
} _ffmpegProcess.Start();
};
_ffmpegProcess.ErrorDataReceived += (_, args) => Console.WriteLine(args.Data);
_ffmpegProcess.Start();
_ffmpegProcess.BeginErrorReadLine();
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) 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 combinedOutputFilePath = $"{_ffmpegFolderPath}\\{songName}_combined_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.mp4";
var ffmpegArgs = 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 var processInfo = new ProcessStartInfo
{ {