Browse Source

add nvidia av1 encoder (#2469)

pull/2470/head
Jason Dove 3 months ago committed by GitHub
parent
commit
e3af0f0b69
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 6
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs
  3. 2
      ErsatzTV.Application/Streaming/HlsSessionWorker.cs
  4. 1
      ErsatzTV.Core/Domain/FFmpegProfileVideoFormat.cs
  5. 1
      ErsatzTV.Core/FFmpeg/FFmpegLibraryHelper.cs
  6. 1
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  7. 6
      ErsatzTV.FFmpeg/Capabilities/Nvidia/CudaHelper.cs
  8. 2
      ErsatzTV.FFmpeg/Capabilities/NvidiaHardwareCapabilities.cs
  9. 14
      ErsatzTV.FFmpeg/Encoder/Nvenc/EncoderAv1Nvenc.cs
  10. 8
      ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs
  11. 1
      ErsatzTV/Pages/Channels.razor
  12. 4
      ErsatzTV/Pages/FFmpegEditor.razor
  13. 5
      ErsatzTV/Validators/FFmpegProfileEditViewModelValidator.cs

2
CHANGELOG.md

@ -60,6 +60,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -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

6
ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs

@ -57,6 +57,12 @@ public class @@ -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;

2
ErsatzTV.Application/Streaming/HlsSessionWorker.cs

@ -587,7 +587,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -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
{

1
ErsatzTV.Core/Domain/FFmpegProfileVideoFormat.cs

@ -7,6 +7,7 @@ public enum FFmpegProfileVideoFormat @@ -7,6 +7,7 @@ public enum FFmpegProfileVideoFormat
H264 = 1,
Hevc = 2,
Mpeg2Video = 3,
Av1 = 4,
Copy = 99
}

1
ErsatzTV.Core/FFmpeg/FFmpegLibraryHelper.cs

@ -33,6 +33,7 @@ public static class FFmpegLibraryHelper @@ -33,6 +33,7 @@ public static class FFmpegLibraryHelper
{
FFmpegProfileVideoFormat.H264 => VideoFormat.H264,
FFmpegProfileVideoFormat.Hevc => VideoFormat.Hevc,
FFmpegProfileVideoFormat.Av1 => VideoFormat.Av1,
_ => VideoFormat.Mpeg2Video
};

1
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -1100,6 +1100,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -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,

6
ErsatzTV.FFmpeg/Capabilities/Nvidia/CudaHelper.cs

@ -12,10 +12,14 @@ internal static class CudaHelper @@ -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);

2
ErsatzTV.FFmpeg/Capabilities/NvidiaHardwareCapabilities.cs

@ -105,6 +105,8 @@ public class NvidiaHardwareCapabilities(CudaDevice cudaDevice, IFFmpegCapabiliti @@ -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
};

14
ErsatzTV.FFmpeg/Encoder/Nvenc/EncoderAv1Nvenc.cs

@ -0,0 +1,14 @@ @@ -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
};
}

8
ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs

@ -74,6 +74,11 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -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 @@ -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
ErsatzTV/Pages/Channels.razor

@ -209,6 +209,7 @@ @@ -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
ErsatzTV/Pages/FFmpegEditor.razor

@ -67,6 +67,10 @@ @@ -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">

5
ErsatzTV/Validators/FFmpegProfileEditViewModelValidator.cs

@ -18,7 +18,8 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi @@ -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 @@ -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(

Loading…
Cancel
Save