windows nvidia h264 workaround (#1487)

* work around bad h264_cuvid behavior on windows with ffmpeg snapshot

* use latest ffmpeg build on windows

* nvdec => cuda
This commit is contained in:
Jason Dove
2023-10-16 11:40:12 -05:00
committed by GitHub
parent 14a88bd225
commit f5060522aa
7 changed files with 35 additions and 19 deletions
+1 -1
View File
@@ -208,7 +208,7 @@ jobs:
id: downloadffmpeg
name: Download ffmpeg
with:
url: "https://github.com/GyanD/codexffmpeg/releases/download/2023-10-04-git-9078dc0c52/ffmpeg-2023-10-04-git-9078dc0c52-full_build.7z"
url: "https://github.com/GyanD/codexffmpeg/releases/download/2023-10-16-git-5ddab49d48/ffmpeg-2023-10-16-git-5ddab49d48-full_build.7z"
target: ffmpeg/
- name: Build
@@ -0,0 +1,13 @@
namespace ErsatzTV.FFmpeg.Decoder.Cuvid;
public class DecoderImplicitCuda : DecoderBase
{
protected override FrameDataLocation OutputFrameDataLocation => FrameDataLocation.Hardware;
public override string Name => string.Empty;
public override IList<string> InputOptions(InputFile inputFile) =>
new List<string>
{
"-hwaccel_output_format",
"cuda"
};
}
@@ -19,7 +19,7 @@ public class EncoderHevcNvenc : EncoderBase
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions =>
new[] { "-c:v", "hevc_nvenc", "-b_ref_mode", _bFrames ? "1" : "0" };
new[] { "-c:v", "hevc_nvenc", "-tag:v", "hvc1", "-b_ref_mode", _bFrames ? "1" : "0" };
public override FrameState NextState(FrameState currentState) => currentState with
{
@@ -51,11 +51,6 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
_logger = logger;
}
protected override bool IsNvidiaOnWindows(FFmpegState ffmpegState) =>
_runtimeInfo.IsOSPlatform(OSPlatform.Windows) &&
(ffmpegState.EncoderHardwareAccelerationMode is HardwareAccelerationMode.Nvenc ||
ffmpegState.DecoderHardwareAccelerationMode is HardwareAccelerationMode.Nvenc);
protected override FFmpegState SetAccelState(
VideoStream videoStream,
FFmpegState ffmpegState,
@@ -101,6 +96,13 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
FFmpegState ffmpegState,
PipelineContext context)
{
if (NeedsCudaWorkaround(ffmpegState, videoStream.Codec))
{
var cuda = new DecoderImplicitCuda();
videoInputFile.AddOption(cuda);
return cuda;
}
Option<IDecoder> maybeDecoder = (ffmpegState.DecoderHardwareAccelerationMode, videoStream.Codec) switch
{
(HardwareAccelerationMode.Nvenc, VideoFormat.Hevc) => new DecoderHevcCuvid(HardwareAccelerationMode.Nvenc),
@@ -645,4 +647,15 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
return currentState;
}
// the combination of:
// - windows
// - ffmpeg 6.1 snapshot (where readrate_initial_burst option is present)
// - h264_cuvid
// appears to cause jitter, so use implicit cuda decoder in that specific case
private bool NeedsCudaWorkaround(FFmpegState ffmpegState, string videoFormat) =>
_runtimeInfo.IsOSPlatform(OSPlatform.Windows)
&& _ffmpegCapabilities.HasOption(FFmpegKnownOption.ReadrateInitialBurst)
&& ffmpegState.DecoderHardwareAccelerationMode is HardwareAccelerationMode.Nvenc
&& videoFormat == VideoFormat.H264;
}
@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.FFmpeg.Decoder;
using ErsatzTV.FFmpeg.Encoder;
@@ -12,7 +11,6 @@ using ErsatzTV.FFmpeg.OutputFormat;
using ErsatzTV.FFmpeg.OutputOption;
using ErsatzTV.FFmpeg.OutputOption.Metadata;
using ErsatzTV.FFmpeg.Protocol;
using ErsatzTV.FFmpeg.Runtime;
using Microsoft.Extensions.Logging;
namespace ErsatzTV.FFmpeg.Pipeline;
@@ -404,7 +402,6 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
}
protected abstract bool IsIntelVaapiOrQsv(FFmpegState ffmpegState);
protected abstract bool IsNvidiaOnWindows(FFmpegState ffmpegState);
protected abstract FFmpegState SetAccelState(
VideoStream videoStream,
@@ -643,13 +640,6 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
};
}
// TODO: when ffmpeg/nvenc stops being weird on windows, remove this workaround
if (IsNvidiaOnWindows(ffmpegState))
{
// disable initial burst
initialBurst = 0;
}
_audioInputFile.Iter(a => a.AddOption(new ReadrateInputOption(_ffmpegCapabilities, initialBurst, _logger)));
videoInputFile.AddOption(new ReadrateInputOption(_ffmpegCapabilities, initialBurst, _logger));
}
@@ -37,8 +37,6 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase
protected override bool IsIntelVaapiOrQsv(FFmpegState ffmpegState) => false;
protected override bool IsNvidiaOnWindows(FFmpegState ffmpegState) => false;
protected override FFmpegState SetAccelState(
VideoStream videoStream,
FFmpegState ffmpegState,
+2
View File
@@ -53,11 +53,13 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=muxdelay/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=muxpreload/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=nostats/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=nvdec/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pixfmt/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=playout/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Playouts/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=probesize/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Radeon/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=readrate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Segmenter/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=setsar/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=showtitle/@EntryIndexedValue">True</s:Boolean>