feat: accelerate ffmpeg encoding with intel gpu

This commit is contained in:
2026-08-14 01:46:08 +08:00
parent 83b5ea042d
commit 7a33b2c6e3
5 changed files with 261 additions and 58 deletions
@@ -419,6 +419,90 @@ public sealed class FfmpegFailureClassificationTests
Assert.Contains("/dev/dri/renderD129", vaapiArguments);
}
[Fact]
public void IntelEncoderCandidates_PreferQsvThenVaapiForEachRenderDevice()
{
var candidates = FfmpegService.BuildIntelVideoEncoderCandidates(
["/dev/dri/renderD128", "/dev/dri/renderD129"]);
Assert.Equal(
[
new RecoveryVideoEncoderSelection(RecoveryVideoEncoderKind.Qsv, "/dev/dri/renderD128"),
new RecoveryVideoEncoderSelection(RecoveryVideoEncoderKind.Qsv, "/dev/dri/renderD129"),
new RecoveryVideoEncoderSelection(RecoveryVideoEncoderKind.Vaapi, "/dev/dri/renderD128"),
new RecoveryVideoEncoderSelection(RecoveryVideoEncoderKind.Vaapi, "/dev/dri/renderD129")
],
candidates);
}
[Fact]
public void Mp4Repair_WithQsv_UsesHardwareAndPlacesDeviceBeforeInput()
{
var arguments = FfmpegService.BuildMp4FinalizeArgumentList(
"/records/input.ts",
"/records/output.mp4",
FfmpegService.Mp4FinalizeStrategy.RepairTranscode,
videoEncoder: new RecoveryVideoEncoderSelection(RecoveryVideoEncoderKind.Qsv, "/dev/dri/renderD128"));
var argumentList = arguments.ToList();
Assert.True(argumentList.IndexOf("-qsv_device") < argumentList.IndexOf("-i"));
Assert.Contains("h264_qsv", arguments);
Assert.DoesNotContain("hwupload", string.Join(',', arguments));
Assert.DoesNotContain("libx264", arguments);
Assert.Contains("aac", arguments);
}
[Fact]
public void Mp4Repair_SoftwareFallback_UsesLibx264()
{
var arguments = FfmpegService.BuildMp4FinalizeArgumentList(
"/records/input.ts",
"/records/output.mp4",
FfmpegService.Mp4FinalizeStrategy.RepairTranscode,
videoEncoder: RecoveryVideoEncoderSelection.Software);
Assert.Contains("libx264", arguments);
Assert.DoesNotContain("h264_qsv", arguments);
Assert.DoesNotContain("h264_vaapi", arguments);
Assert.DoesNotContain("-vf", arguments);
Assert.DoesNotContain("-fps_mode", arguments);
}
[Fact]
public void BalancedMp4_WithVaapi_UsesHardwareWhileStreamCopyRemainsUnchanged()
{
var vaapi = new RecoveryVideoEncoderSelection(RecoveryVideoEncoderKind.Vaapi, "/dev/dri/renderD128");
var balanced = FfmpegService.BuildArgumentList(
"https://cdn.example.test/live.flv", "/tmp/output.mp4",
RecordOutputFormat.Mp4, RecordSaveMode.SingleFile, 1,
RecordingTemplateType.BalancedMp4, true, 10, 30_000_000, 30,
null, "flv", "h264", FfmpegService.FfmpegInputOptionProfile.Baseline, vaapi);
var streamCopy = FfmpegService.BuildArgumentList(
"https://cdn.example.test/live.flv", "/tmp/output.mp4",
RecordOutputFormat.Mp4, RecordSaveMode.SingleFile, 1,
RecordingTemplateType.StreamCopy, true, 10, 30_000_000, 30,
null, "flv", "h264", FfmpegService.FfmpegInputOptionProfile.Baseline, vaapi);
var balancedList = balanced.ToList();
Assert.True(balancedList.IndexOf("-vaapi_device") < balancedList.IndexOf("-i"));
Assert.Contains("h264_vaapi", balanced);
Assert.DoesNotContain("libx264", balanced);
Assert.Contains("copy", streamCopy);
Assert.DoesNotContain("h264_vaapi", streamCopy);
Assert.DoesNotContain("libx264", streamCopy);
}
[Theory]
[InlineData("Permission denied", false)]
[InlineData("Invalid data found when processing input", false)]
[InlineData("No VA display found for device /dev/dri/renderD128", true)]
[InlineData("Failed to create QSV device", true)]
[InlineData("Failed to upload frame: -5", true)]
public void OnlyHardwareEncoderFailures_EnableSoftwareFallback(string line, bool expected)
{
Assert.Equal(expected, FfmpegService.IsHardwareEncoderFailureLine(line));
}
[Fact]
public void TimestampTranscode_WithQsv_PlacesDeviceBeforeInputAndKeepsTimestampFilters()
{
@@ -443,7 +527,8 @@ public sealed class FfmpegFailureClassificationTests
Assert.True(argumentList.IndexOf("-qsv_device") < argumentList.IndexOf("-i"));
Assert.Contains("h264_qsv", arguments);
Assert.Contains(arguments, item => item.Contains("setpts=PTS-STARTPTS", StringComparison.Ordinal));
Assert.Contains(arguments, item => item.Contains("hwupload", StringComparison.Ordinal));
Assert.Contains(arguments, item => item.Contains("format=nv12", StringComparison.Ordinal));
Assert.DoesNotContain(arguments, item => item.Contains("hwupload", StringComparison.Ordinal));
Assert.Contains("aresample=async=1:first_pts=0,asetpts=PTS-STARTPTS", arguments);
}
}