176 lines
7.9 KiB
C#
176 lines
7.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Paca.Core.Media;
|
|
using Paca.Core.Platform;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Core;
|
|
|
|
public class GpuHardwareAccelerationProfilerTests
|
|
{
|
|
private sealed class MockProbeProcessRunner : IProcessRunner
|
|
{
|
|
private readonly Func<ProcessSpec, ProcessResult> _handler;
|
|
|
|
public MockProbeProcessRunner(Func<ProcessSpec, ProcessResult> handler)
|
|
{
|
|
_handler = handler;
|
|
}
|
|
|
|
public Task<ProcessResult> RunAsync(ProcessSpec spec, Action<string, string>? onLine, CancellationToken ct)
|
|
{
|
|
return Task.FromResult(_handler(spec));
|
|
}
|
|
}
|
|
|
|
private const string FullRtx4090EncodersOutput =
|
|
"Encoders:\n" +
|
|
" V..... h264_nvenc NVIDIA NVENC H.264 encoder (codec h264)\n" +
|
|
" V..... hevc_nvenc NVIDIA NVENC hevc encoder (codec hevc)\n" +
|
|
" V..... av1_nvenc NVIDIA NVENC av1 encoder (codec av1)\n" +
|
|
" V..... libx264 libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (codec h264)\n" +
|
|
" V..... libx265 libx265 H.265 / HEVC (codec hevc)\n" +
|
|
" V..... libsvtav1 SVT-AV1(Scalable Video Technology for AV1) encoder (codec av1)\n";
|
|
|
|
private const string IntelArcEncodersOutput =
|
|
"Encoders:\n" +
|
|
" V..... h264_qsv H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (Intel Quick Sync Video acceleration) (codec h264)\n" +
|
|
" V..... hevc_qsv HEVC (Intel Quick Sync Video acceleration) (codec hevc)\n" +
|
|
" V..... av1_qsv AV1 (Intel Quick Sync Video acceleration) (codec av1)\n" +
|
|
" V..... libx264 libx264 H.264 (codec h264)\n";
|
|
|
|
private const string AmdRadeon7000EncodersOutput =
|
|
"Encoders:\n" +
|
|
" V..... h264_amf AMD AMF H.264 Encoder (codec h264)\n" +
|
|
" V..... hevc_amf AMD AMF HEVC Encoder (codec hevc)\n" +
|
|
" V..... av1_amf AMD AMF AV1 Encoder (codec av1)\n" +
|
|
" V..... libx264 libx264 H.264 (codec h264)\n";
|
|
|
|
[Fact]
|
|
public void GpuCapabilities_NVENC_H264_HEVC_AV1_전부_파싱_검증()
|
|
{
|
|
var caps = GpuHardwareAccelerationProfiler.ParseCapabilities(FullRtx4090EncodersOutput);
|
|
|
|
Assert.True(caps.Supports(GpuEncoderBackend.NvidiaNvenc, VideoCodecTarget.H264));
|
|
Assert.True(caps.Supports(GpuEncoderBackend.NvidiaNvenc, VideoCodecTarget.HEVC_H265));
|
|
Assert.True(caps.Supports(GpuEncoderBackend.NvidiaNvenc, VideoCodecTarget.AV1));
|
|
Assert.False(caps.Supports(GpuEncoderBackend.IntelQsv, VideoCodecTarget.AV1));
|
|
}
|
|
|
|
[Fact]
|
|
public void GpuCapabilities_IntelQSV_AMD_AMF_AV1_파싱_검증()
|
|
{
|
|
var intelCaps = GpuHardwareAccelerationProfiler.ParseCapabilities(IntelArcEncodersOutput);
|
|
Assert.True(intelCaps.Supports(GpuEncoderBackend.IntelQsv, VideoCodecTarget.AV1));
|
|
Assert.True(intelCaps.Supports(GpuEncoderBackend.IntelQsv, VideoCodecTarget.HEVC_H265));
|
|
Assert.False(intelCaps.Supports(GpuEncoderBackend.NvidiaNvenc, VideoCodecTarget.AV1));
|
|
|
|
var amdCaps = GpuHardwareAccelerationProfiler.ParseCapabilities(AmdRadeon7000EncodersOutput);
|
|
Assert.True(amdCaps.Supports(GpuEncoderBackend.AmdAmf, VideoCodecTarget.AV1));
|
|
Assert.True(amdCaps.Supports(GpuEncoderBackend.AmdAmf, VideoCodecTarget.HEVC_H265));
|
|
Assert.False(amdCaps.Supports(GpuEncoderBackend.IntelQsv, VideoCodecTarget.AV1));
|
|
}
|
|
|
|
[Fact]
|
|
public void GpuCapabilities_최적_인코더_자동선택_GPU_우선_및_CPU_폴백()
|
|
{
|
|
var rtxCaps = GpuHardwareAccelerationProfiler.ParseCapabilities(FullRtx4090EncodersOutput);
|
|
Assert.Equal("av1_nvenc", rtxCaps.GetOptimalEncoder(VideoCodecTarget.AV1));
|
|
Assert.Equal("hevc_nvenc", rtxCaps.GetOptimalEncoder(VideoCodecTarget.HEVC_H265));
|
|
Assert.Equal("h264_nvenc", rtxCaps.GetOptimalEncoder(VideoCodecTarget.H264));
|
|
|
|
var cpuOnlyCaps = GpuHardwareAccelerationProfiler.ParseCapabilities(
|
|
"Encoders:\n V..... libx264\n V..... libx265\n V..... libsvtav1\n");
|
|
Assert.Equal("libsvtav1", cpuOnlyCaps.GetOptimalEncoder(VideoCodecTarget.AV1));
|
|
Assert.Equal("libx265", cpuOnlyCaps.GetOptimalEncoder(VideoCodecTarget.HEVC_H265));
|
|
Assert.Equal("libx264", cpuOnlyCaps.GetOptimalEncoder(VideoCodecTarget.H264));
|
|
}
|
|
|
|
[Fact]
|
|
public async Task GpuProfiler_실제_런타임_프로빙_미지원시_폴백_검증()
|
|
{
|
|
var runner = new MockProbeProcessRunner(spec =>
|
|
{
|
|
if (spec.Args.Contains("-encoders"))
|
|
{
|
|
return new ProcessResult(0, FullRtx4090EncodersOutput, "");
|
|
}
|
|
|
|
if (spec.Args.Contains("av1_nvenc"))
|
|
{
|
|
return new ProcessResult(1, "", "[av1_nvenc @ 000001] Driver does not support the required nvenc features\nError initializing output stream");
|
|
}
|
|
|
|
if (spec.Args.Contains("hevc_nvenc") || spec.Args.Contains("h264_nvenc"))
|
|
{
|
|
return new ProcessResult(0, "frame= 1 fps=0.0 q=0.0 Lsize=N/A video:0KiB", "");
|
|
}
|
|
|
|
return new ProcessResult(0, "", "");
|
|
});
|
|
|
|
var profiler = new GpuHardwareAccelerationProfiler(runner);
|
|
var report = await profiler.ProfileAllCodecsAsync("ffmpeg.exe", CancellationToken.None);
|
|
|
|
Assert.True(report.IsProbeVerified);
|
|
Assert.Equal("libsvtav1", report.GetBestEncoder(VideoCodecTarget.AV1));
|
|
Assert.Equal("hevc_nvenc", report.GetBestEncoder(VideoCodecTarget.HEVC_H265));
|
|
Assert.Equal("h264_nvenc", report.GetBestEncoder(VideoCodecTarget.H264));
|
|
}
|
|
|
|
[Fact]
|
|
public void GpuProfiler_인코더별_최적_인수_생성_검증()
|
|
{
|
|
var nvencAv1Args = GpuHardwareAccelerationProfiler.BuildEncodingArgs("av1_nvenc", crfOrQuality: 24, preset: "p4");
|
|
Assert.Contains("-c:v", nvencAv1Args);
|
|
Assert.Contains("av1_nvenc", nvencAv1Args);
|
|
Assert.Contains("-cq", nvencAv1Args);
|
|
Assert.Contains("24", nvencAv1Args);
|
|
Assert.Contains("-preset", nvencAv1Args);
|
|
Assert.Contains("p4", nvencAv1Args);
|
|
|
|
var qsvAv1Args = GpuHardwareAccelerationProfiler.BuildEncodingArgs("av1_qsv", crfOrQuality: 26);
|
|
Assert.Contains("av1_qsv", qsvAv1Args);
|
|
Assert.Contains("-global_quality", qsvAv1Args);
|
|
Assert.Contains("26", qsvAv1Args);
|
|
|
|
var svtAv1Args = GpuHardwareAccelerationProfiler.BuildEncodingArgs("libsvtav1", crfOrQuality: 28, preset: "6");
|
|
Assert.Contains("libsvtav1", svtAv1Args);
|
|
Assert.Contains("-crf", svtAv1Args);
|
|
Assert.Contains("28", svtAv1Args);
|
|
}
|
|
|
|
[Fact]
|
|
public void HardwareEncoderDetector_기존_하위호환_및_AV1_확장_검증()
|
|
{
|
|
var sample = FullRtx4090EncodersOutput;
|
|
var caps = HardwareEncoderDetector.ParseCapabilities(sample);
|
|
|
|
Assert.True(caps.HasNvidiaNvenc);
|
|
Assert.True(caps.HasNvencAv1);
|
|
Assert.True(caps.HasNvencHevc);
|
|
|
|
var runner = new MockProbeProcessRunner(_ => new ProcessResult(0, sample, ""));
|
|
var detector = new HardwareEncoderDetector(runner);
|
|
|
|
Assert.Equal("av1_nvenc", detector.GetBestAv1Encoder(caps));
|
|
Assert.Equal("hevc_nvenc", detector.GetBestHevcEncoder(caps));
|
|
Assert.Equal("h264_nvenc", detector.GetBestH264Encoder(caps));
|
|
}
|
|
|
|
[Fact]
|
|
public void HardwareTranscoderStudio_Auto_Backend와_Capabilities_결합시_GPU_인코더_자동선택()
|
|
{
|
|
var caps = GpuHardwareAccelerationProfiler.ParseCapabilities(FullRtx4090EncodersOutput);
|
|
var spec = new TranscodePresetSpec
|
|
{
|
|
Backend = HardwareEncoderBackend.Auto,
|
|
Codec = VideoCodecTarget.AV1
|
|
};
|
|
|
|
var args = HardwareTranscoderStudio.BuildFfmpegTranscodeCommand("in.mp4", "out.mp4", spec, caps);
|
|
Assert.Contains("av1_nvenc", args);
|
|
}
|
|
}
|