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:
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user