add nvidia av1 encoder (#2469)

This commit is contained in:
Jason Dove
2025-09-30 11:43:12 -05:00
committed by GitHub
parent b46de50801
commit e3af0f0b69
13 changed files with 49 additions and 4 deletions
+2
View File
@@ -60,6 +60,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Allow HEVC playback in channel preview
- This is restricted to compatible browsers
- Preview button will be red when preview is disabled due to browser incompatibility
- Add AV1 encoding support with NVIDIA acceleration
- This also requires `HLS Segmenter (fmp4)`
### Fixed
- Fix green output when libplacebo tonemapping is used with NVIDIA acceleration and 10-bit output in FFmpeg Profile
@@ -57,6 +57,12 @@ public class
? FFmpegProfileBitDepth.EightBit
: update.BitDepth;
if (p.HardwareAcceleration is not HardwareAccelerationKind.Nvenc &&
p.VideoFormat is FFmpegProfileVideoFormat.Av1)
{
p.VideoFormat = FFmpegProfileVideoFormat.Hevc;
}
p.VideoBitrate = update.VideoBitrate;
p.VideoBufferSize = update.VideoBufferSize;
p.TonemapAlgorithm = update.TonemapAlgorithm;
@@ -587,7 +587,7 @@ public class HlsSessionWorker : IHlsSessionWorker
}
catch (Exception ex)
{
_logger.LogError(ex, "Error transcoding channel {Channel}", _channelNumber);
_logger.LogError(ex, "Error transcoding channel {Channel} - {Message}", _channelNumber, ex.Message);
try
{
@@ -7,6 +7,7 @@ public enum FFmpegProfileVideoFormat
H264 = 1,
Hevc = 2,
Mpeg2Video = 3,
Av1 = 4,
Copy = 99
}
@@ -33,6 +33,7 @@ public static class FFmpegLibraryHelper
{
FFmpegProfileVideoFormat.H264 => VideoFormat.H264,
FFmpegProfileVideoFormat.Hevc => VideoFormat.Hevc,
FFmpegProfileVideoFormat.Av1 => VideoFormat.Av1,
_ => VideoFormat.Mpeg2Video
};
@@ -1100,6 +1100,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
private static string GetVideoFormat(FFmpegPlaybackSettings playbackSettings) =>
playbackSettings.VideoFormat switch
{
FFmpegProfileVideoFormat.Av1 => VideoFormat.Av1,
FFmpegProfileVideoFormat.Hevc => VideoFormat.Hevc,
FFmpegProfileVideoFormat.H264 => VideoFormat.H264,
FFmpegProfileVideoFormat.Mpeg2Video => VideoFormat.Mpeg2Video,
@@ -12,10 +12,14 @@ internal static class CudaHelper
private static bool _initialized;
private static readonly Lock Lock = new();
public static Guid Av1CodecGuid = Guid.Parse("0A352289-0AA7-4759-862D-5D15CD16D254");
public static Guid Av1ProfileGuid = Guid.Parse("5f2a39f5-f14e-4f95-9a9e-b76d568fcf97");
private static readonly Dictionary<string, Guid> AllEncoders = new()
{
[VideoFormat.H264] = NvEncCodecGuids.H264,
[VideoFormat.Hevc] = NvEncCodecGuids.Hevc
[VideoFormat.Hevc] = NvEncCodecGuids.Hevc,
[VideoFormat.Av1] = Av1CodecGuid
};
private sealed record Decoder(CuVideoChromaFormat ChromaFormat, CuVideoCodec VideoCodec, int BitDepth);
@@ -105,6 +105,8 @@ public class NvidiaHardwareCapabilities(CudaDevice cudaDevice, IFFmpegCapabiliti
// high10 is for libx264, nvenc needs high444
(VideoFormat.H264, VideoProfile.High10, _) => NvEncProfileGuids.H264High444,
(VideoFormat.Av1, _, _) => CudaHelper.Av1ProfileGuid,
_ => NvEncProfileGuids.H264Main
};
@@ -0,0 +1,14 @@
using ErsatzTV.FFmpeg.Format;
namespace ErsatzTV.FFmpeg.Encoder.Nvenc;
public class EncoderAv1Nvenc : EncoderBase
{
public override string Name => "av1_nvenc";
public override StreamKind Kind => StreamKind.Video;
public override FrameState NextState(FrameState currentState) => currentState with
{
VideoFormat = VideoFormat.Av1
};
}
@@ -74,6 +74,11 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
encodeCapability = FFmpegCapability.Software;
}
if (desiredState.VideoFormat is VideoFormat.Av1 && ffmpegState.OutputFormat is not OutputFormatKind.HlsMp4)
{
throw new NotSupportedException("AV1 output is only supported with HLS Segmenter (fmp4)");
}
// mpeg2_cuvid seems to have issues when yadif_cuda is used, so just use software decoding
if (context.ShouldDeinterlace && videoStream.Codec == VideoFormat.Mpeg2Video)
{
@@ -311,6 +316,9 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
(HardwareAccelerationMode.Nvenc, VideoFormat.H264) =>
new EncoderH264Nvenc(desiredState.VideoProfile, desiredState.VideoPreset),
(HardwareAccelerationMode.Nvenc, VideoFormat.Av1) => new EncoderAv1Nvenc(),
(HardwareAccelerationMode.None, VideoFormat.Av1) => throw new NotSupportedException("AV1 software encoding is not supported"),
// don't pass NVENC profile down to libx264
(_, _) => GetSoftwareEncoder(ffmpegState, currentState, desiredState with { VideoProfile = Option<string>.None })
};
+1
View File
@@ -209,6 +209,7 @@
{
string videoCodec = profile.VideoFormat switch
{
FFmpegProfileVideoFormat.Av1 => "av01.0.01M.08",
FFmpegProfileVideoFormat.Hevc => "hvc1.1.6.L93.B0",
FFmpegProfileVideoFormat.H264 => "avc1.4D4028",
_ => string.Empty
+4
View File
@@ -67,6 +67,10 @@
<MudSelectItem Value="@FFmpegProfileVideoFormat.H264">h264</MudSelectItem>
<MudSelectItem Value="@FFmpegProfileVideoFormat.Hevc">hevc</MudSelectItem>
<MudSelectItem Value="@FFmpegProfileVideoFormat.Mpeg2Video">mpeg-2</MudSelectItem>
@if (_model.HardwareAcceleration is HardwareAccelerationKind.Nvenc)
{
<MudSelectItem Value="@FFmpegProfileVideoFormat.Av1">av1</MudSelectItem>
}
</MudSelect>
</MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
@@ -18,7 +18,8 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi
private static readonly List<FFmpegProfileVideoFormat> NvencFormats =
[
FFmpegProfileVideoFormat.H264,
FFmpegProfileVideoFormat.Hevc
FFmpegProfileVideoFormat.Hevc,
FFmpegProfileVideoFormat.Av1
];
private static readonly List<FFmpegProfileVideoFormat> VaapiFormats =
@@ -77,7 +78,7 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi
() =>
{
RuleFor(x => x.VideoFormat).Must(c => NvencFormats.Contains(c))
.WithMessage("NVENC supports formats (h264, hevc)");
.WithMessage("NVENC supports formats (h264, hevc, av1)");
});
When(