mirror of https://github.com/ErsatzTV/ErsatzTV.git
14 changed files with 350 additions and 62 deletions
@ -0,0 +1,3 @@ |
|||||||
|
namespace ErsatzTV.FFmpeg.Capabilities.Nvidia; |
||||||
|
|
||||||
|
public record CudaDevice(int Handle, string Model, Version Version); |
||||||
@ -0,0 +1,132 @@ |
|||||||
|
using System.Globalization; |
||||||
|
using System.Text; |
||||||
|
using ErsatzTV.FFmpeg.Format; |
||||||
|
using Lennox.NvEncSharp; |
||||||
|
|
||||||
|
namespace ErsatzTV.FFmpeg.Capabilities.Nvidia; |
||||||
|
|
||||||
|
internal static class CudaHelper |
||||||
|
{ |
||||||
|
private static bool _success; |
||||||
|
private static bool _initialized; |
||||||
|
private static readonly Lock Lock = new(); |
||||||
|
|
||||||
|
private static readonly Dictionary<string, Guid> AllCodecs = new() |
||||||
|
{ |
||||||
|
[VideoFormat.H264] = NvEncCodecGuids.H264, |
||||||
|
[VideoFormat.Hevc] = NvEncCodecGuids.Hevc |
||||||
|
}; |
||||||
|
|
||||||
|
private static bool EnsureInit() |
||||||
|
{ |
||||||
|
if (_initialized) |
||||||
|
{ |
||||||
|
return _success; |
||||||
|
} |
||||||
|
|
||||||
|
lock (Lock) |
||||||
|
{ |
||||||
|
if (_initialized) |
||||||
|
{ |
||||||
|
return _success; |
||||||
|
} |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
LibNvEnc.TryInitialize(out string? error); |
||||||
|
if (string.IsNullOrEmpty(error)) |
||||||
|
{ |
||||||
|
LibCuda.Initialize(); |
||||||
|
_success = true; |
||||||
|
} |
||||||
|
} |
||||||
|
catch (LibNvEncException) |
||||||
|
{ |
||||||
|
_success = false; |
||||||
|
} |
||||||
|
|
||||||
|
_initialized = true; |
||||||
|
} |
||||||
|
|
||||||
|
return _success; |
||||||
|
} |
||||||
|
|
||||||
|
internal static Option<List<CudaDevice>> GetDevices() |
||||||
|
{ |
||||||
|
var result = new List<CudaDevice>(); |
||||||
|
|
||||||
|
if (!EnsureInit()) |
||||||
|
{ |
||||||
|
return Option<List<CudaDevice>>.None; |
||||||
|
} |
||||||
|
|
||||||
|
foreach (var description in CuDevice.GetDescriptions()) |
||||||
|
{ |
||||||
|
var device = description.Device; |
||||||
|
|
||||||
|
string name = device.GetName(); |
||||||
|
int nullIndex = name.IndexOf('\0'); |
||||||
|
if (nullIndex > 0) |
||||||
|
{ |
||||||
|
name = name[..nullIndex]; |
||||||
|
} |
||||||
|
|
||||||
|
int major = device.GetAttribute(CuDeviceAttribute.ComputeCapabilityMajor); |
||||||
|
int minor = device.GetAttribute(CuDeviceAttribute.ComputeCapabilityMinor); |
||||||
|
|
||||||
|
result.Add(new CudaDevice(device.Handle, name, new Version(major, minor))); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
internal static string GetDeviceDetails(CudaDevice device) |
||||||
|
{ |
||||||
|
var sb = new StringBuilder(); |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
var dev = CuDevice.GetDevice(device.Handle); |
||||||
|
using var context = dev.CreateContext(); |
||||||
|
var sessionParams = new NvEncOpenEncodeSessionExParams |
||||||
|
{ |
||||||
|
Version = LibNvEnc.NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER, |
||||||
|
ApiVersion = LibNvEnc.NVENCAPI_VERSION, |
||||||
|
Device = context.Handle, |
||||||
|
DeviceType = NvEncDeviceType.Cuda |
||||||
|
}; |
||||||
|
|
||||||
|
var encoder = LibNvEnc.OpenEncoder(ref sessionParams); |
||||||
|
try |
||||||
|
{ |
||||||
|
sb.AppendLine(" Encoding:"); |
||||||
|
IReadOnlyList<Guid> codecGuids = encoder.GetEncodeGuids(); |
||||||
|
foreach ((string codecName, Guid codecGuid) in AllCodecs) |
||||||
|
{ |
||||||
|
if (codecGuids.Contains(codecGuid)) |
||||||
|
{ |
||||||
|
sb.AppendLine(CultureInfo.InvariantCulture, $" - Supports {codecName} 8-bit"); |
||||||
|
|
||||||
|
var cap = new NvEncCapsParam { CapsToQuery = NvEncCaps.Support10bitEncode }; |
||||||
|
var capsVal = 0; |
||||||
|
encoder.GetEncodeCaps(codecGuid, ref cap, ref capsVal); |
||||||
|
if (capsVal > 0) |
||||||
|
{ |
||||||
|
sb.AppendLine(CultureInfo.InvariantCulture, $" - Supports {codecName} 10-bit"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
finally |
||||||
|
{ |
||||||
|
encoder.DestroyEncoder(); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (Exception) |
||||||
|
{ |
||||||
|
// do nothing
|
||||||
|
} |
||||||
|
|
||||||
|
return sb.ToString(); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
using System.Reflection; |
||||||
|
using System.Runtime.InteropServices; |
||||||
|
|
||||||
|
namespace ErsatzTV.FFmpeg.Capabilities.Nvidia; |
||||||
|
|
||||||
|
public static class NvEncSharpRedirector |
||||||
|
{ |
||||||
|
static NvEncSharpRedirector() |
||||||
|
{ |
||||||
|
NativeLibrary.SetDllImportResolver(typeof(Lennox.NvEncSharp.LibCuda).Assembly, Resolver); |
||||||
|
} |
||||||
|
|
||||||
|
private static IntPtr Resolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) |
||||||
|
{ |
||||||
|
if (libraryName.Equals("nvEncodeAPI64.dll", StringComparison.OrdinalIgnoreCase)) |
||||||
|
{ |
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
||||||
|
return NativeLibrary.Load("libnvidia-encode.so", assembly, searchPath); |
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
||||||
|
return NativeLibrary.Load("nvEncodeAPI64.dll", assembly, searchPath); |
||||||
|
} |
||||||
|
|
||||||
|
if (libraryName.Equals("nvEncodeAPI.dll", StringComparison.OrdinalIgnoreCase)) |
||||||
|
{ |
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
||||||
|
return NativeLibrary.Load("libnvidia-encode.so", assembly, searchPath); |
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
||||||
|
return NativeLibrary.Load("nvEncodeAPI.dll", assembly, searchPath); |
||||||
|
} |
||||||
|
|
||||||
|
if (libraryName.Equals("nvcuda.dll", StringComparison.OrdinalIgnoreCase)) |
||||||
|
{ |
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
||||||
|
return NativeLibrary.Load("libcuda.so", assembly, searchPath); |
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) |
||||||
|
return NativeLibrary.Load("nvcuda.dll", assembly, searchPath); |
||||||
|
} |
||||||
|
|
||||||
|
return IntPtr.Zero; |
||||||
|
} |
||||||
|
|
||||||
|
public static void Init() { } |
||||||
|
} |
||||||
Loading…
Reference in new issue