add amf acceleration (#947)

This commit is contained in:
Jason Dove
2022-09-03 10:39:54 -05:00
committed by GitHub
parent acc22fcb62
commit 3972e3603b
16 changed files with 112 additions and 11 deletions
+1
View File
@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- When a title is specified, audio streams that contain that title (case-insensitive search) will be prioritized - When a title is specified, audio streams that contain that title (case-insensitive search) will be prioritized
- This can be helpful for creating channels that use commentary tracks - This can be helpful for creating channels that use commentary tracks
- External tooling exists to easily update title/name metadata if your audio streams don't already have this metadata - External tooling exists to easily update title/name metadata if your audio streams don't already have this metadata
- Add `Amf` hardware acceleration option for AMD GPUs on Windows
## [0.6.6-beta] - 2022-08-17 ## [0.6.6-beta] - 2022-08-17
### Fixed ### Fixed
@@ -168,6 +168,11 @@ public class TranscodingTests
HardwareAccelerationKind.VideoToolbox HardwareAccelerationKind.VideoToolbox
}; };
public static HardwareAccelerationKind[] AmfAcceleration =
{
HardwareAccelerationKind.Amf
};
public static HardwareAccelerationKind[] QsvAcceleration = public static HardwareAccelerationKind[] QsvAcceleration =
{ {
HardwareAccelerationKind.Qsv HardwareAccelerationKind.Qsv
@@ -192,11 +197,11 @@ public class TranscodingTests
[ValueSource(typeof(TestData), nameof(TestData.VideoFormats))] [ValueSource(typeof(TestData), nameof(TestData.VideoFormats))]
FFmpegProfileVideoFormat profileVideoFormat, FFmpegProfileVideoFormat profileVideoFormat,
// [ValueSource(typeof(TestData), nameof(TestData.NoAcceleration))] HardwareAccelerationKind profileAcceleration) // [ValueSource(typeof(TestData), nameof(TestData.NoAcceleration))] HardwareAccelerationKind profileAcceleration)
[ValueSource(typeof(TestData), nameof(TestData.NvidiaAcceleration))] // [ValueSource(typeof(TestData), nameof(TestData.NvidiaAcceleration))] HardwareAccelerationKind profileAcceleration)
HardwareAccelerationKind profileAcceleration)
// [ValueSource(typeof(TestData), nameof(TestData.VaapiAcceleration))] HardwareAccelerationKind profileAcceleration) // [ValueSource(typeof(TestData), nameof(TestData.VaapiAcceleration))] HardwareAccelerationKind profileAcceleration)
// [ValueSource(typeof(TestData), nameof(TestData.QsvAcceleration))] HardwareAccelerationKind profileAcceleration) // [ValueSource(typeof(TestData), nameof(TestData.QsvAcceleration))] HardwareAccelerationKind profileAcceleration)
// [ValueSource(typeof(TestData), nameof(TestData.VideoToolboxAcceleration))] HardwareAccelerationKind profileAcceleration) // [ValueSource(typeof(TestData), nameof(TestData.VideoToolboxAcceleration))] HardwareAccelerationKind profileAcceleration)
[ValueSource(typeof(TestData), nameof(TestData.AmfAcceleration))] HardwareAccelerationKind profileAcceleration)
{ {
if (inputFormat.Encoder is "mpeg1video" or "msmpeg4v2" or "msmpeg4v3") if (inputFormat.Encoder is "mpeg1video" or "msmpeg4v2" or "msmpeg4v3")
{ {
@@ -6,5 +6,6 @@ public enum HardwareAccelerationKind
Qsv = 1, Qsv = 1,
Nvenc = 2, Nvenc = 2,
Vaapi = 3, Vaapi = 3,
VideoToolbox = 4 VideoToolbox = 4,
Amf = 5
} }
@@ -169,6 +169,7 @@ public class FFmpegComplexFilterBuilder
_videoDecoder.Contains("cuvid")), _videoDecoder.Contains("cuvid")),
HardwareAccelerationKind.Qsv => !isSong, HardwareAccelerationKind.Qsv => !isSong,
HardwareAccelerationKind.VideoToolbox => false, HardwareAccelerationKind.VideoToolbox => false,
HardwareAccelerationKind.Amf => false,
_ => false _ => false
}; };
@@ -200,6 +201,7 @@ public class FFmpegComplexFilterBuilder
bool usesHardwareFilters = acceleration != HardwareAccelerationKind.None && bool usesHardwareFilters = acceleration != HardwareAccelerationKind.None &&
acceleration != HardwareAccelerationKind.VideoToolbox && acceleration != HardwareAccelerationKind.VideoToolbox &&
acceleration != HardwareAccelerationKind.Amf &&
!isHardwareDecode && !isHardwareDecode &&
(_deinterlace || _scaleToSize.IsSome); (_deinterlace || _scaleToSize.IsSome);
@@ -627,6 +627,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
HardwareAccelerationKind.Qsv => HardwareAccelerationMode.Qsv, HardwareAccelerationKind.Qsv => HardwareAccelerationMode.Qsv,
HardwareAccelerationKind.Vaapi => HardwareAccelerationMode.Vaapi, HardwareAccelerationKind.Vaapi => HardwareAccelerationMode.Vaapi,
HardwareAccelerationKind.VideoToolbox => HardwareAccelerationMode.VideoToolbox, HardwareAccelerationKind.VideoToolbox => HardwareAccelerationMode.VideoToolbox,
HardwareAccelerationKind.Amf => HardwareAccelerationMode.Amf,
_ => HardwareAccelerationMode.None _ => HardwareAccelerationMode.None
}; };
} }
@@ -0,0 +1,15 @@
using ErsatzTV.FFmpeg.Format;
namespace ErsatzTV.FFmpeg.Encoder.Amf;
public class EncoderH264Amf : EncoderBase
{
public override string Name => "h264_amf";
public override StreamKind Kind => StreamKind.Video;
public override FrameState NextState(FrameState currentState) => currentState with
{
VideoFormat = VideoFormat.H264,
FrameDataLocation = FrameDataLocation.Hardware
};
}
@@ -0,0 +1,15 @@
using ErsatzTV.FFmpeg.Format;
namespace ErsatzTV.FFmpeg.Encoder.Amf;
public class EncoderHevcAmf : EncoderBase
{
public override string Name => "hevc_amf";
public override StreamKind Kind => StreamKind.Video;
public override FrameState NextState(FrameState currentState) => currentState with
{
VideoFormat = VideoFormat.Hevc,
FrameDataLocation = FrameDataLocation.Hardware
};
}
@@ -1,4 +1,5 @@
using ErsatzTV.FFmpeg.Capabilities; using ErsatzTV.FFmpeg.Capabilities;
using ErsatzTV.FFmpeg.Encoder.Amf;
using ErsatzTV.FFmpeg.Encoder.Nvenc; using ErsatzTV.FFmpeg.Encoder.Nvenc;
using ErsatzTV.FFmpeg.Encoder.Qsv; using ErsatzTV.FFmpeg.Encoder.Qsv;
using ErsatzTV.FFmpeg.Encoder.Vaapi; using ErsatzTV.FFmpeg.Encoder.Vaapi;
@@ -72,6 +73,13 @@ public static class AvailableEncoders
(HardwareAccelerationMode.VideoToolbox, VideoFormat.H264) when hardwareCapabilities.CanEncode( (HardwareAccelerationMode.VideoToolbox, VideoFormat.H264) when hardwareCapabilities.CanEncode(
VideoFormat.H264, VideoFormat.H264,
desiredState.PixelFormat) => new EncoderH264VideoToolbox(), desiredState.PixelFormat) => new EncoderH264VideoToolbox(),
(HardwareAccelerationMode.Amf, VideoFormat.Hevc) when hardwareCapabilities.CanEncode(
VideoFormat.Hevc,
desiredState.PixelFormat) => new EncoderHevcAmf(),
(HardwareAccelerationMode.Amf, VideoFormat.H264) when hardwareCapabilities.CanEncode(
VideoFormat.H264,
desiredState.PixelFormat) => new EncoderH264Amf(),
(_, VideoFormat.Hevc) => new EncoderLibx265(currentState), (_, VideoFormat.Hevc) => new EncoderLibx265(currentState),
(_, VideoFormat.H264) => new EncoderLibx264(), (_, VideoFormat.H264) => new EncoderLibx264(),
+5 -5
View File
@@ -173,7 +173,8 @@ public class ComplexFilter : IPipelineStep
if (_maybeSubtitleInputFile.Map(s => !s.IsImageBased).IfNone(false) && if (_maybeSubtitleInputFile.Map(s => !s.IsImageBased).IfNone(false) &&
_ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Vaapi && _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Vaapi &&
_ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.VideoToolbox) _ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.VideoToolbox &&
_ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Amf)
{ {
uploadDownloadFilter = new HardwareDownloadFilter(_currentState).Filter; uploadDownloadFilter = new HardwareDownloadFilter(_currentState).Filter;
} }
@@ -230,10 +231,9 @@ public class ComplexFilter : IPipelineStep
if (filter != string.Empty) if (filter != string.Empty)
{ {
string tempVideoLabel = string.IsNullOrWhiteSpace(videoFilterComplex) && string tempVideoLabel = videoLabel.StartsWith('[') && videoLabel.EndsWith(']')
string.IsNullOrWhiteSpace(watermarkFilterComplex) ? videoLabel
? $"[{videoLabel}]" : $"[{videoLabel}]";
: videoLabel;
// vaapi uses software overlay and needs to upload // vaapi uses software overlay and needs to upload
// videotoolbox seems to require a hwupload for hevc // videotoolbox seems to require a hwupload for hevc
@@ -25,6 +25,9 @@ public class SubtitleHardwareUploadFilter : BaseFilter
// leave videotoolbox in software since we use a software overlay filter // leave videotoolbox in software since we use a software overlay filter
HardwareAccelerationMode.VideoToolbox => string.Empty, HardwareAccelerationMode.VideoToolbox => string.Empty,
// leave amf in software since we use a software overlay filter
HardwareAccelerationMode.Amf => string.Empty,
_ => "hwupload" _ => "hwupload"
}; };
@@ -24,6 +24,9 @@ public class WatermarkHardwareUploadFilter : BaseFilter
// leave videotoolbox in software since we use a software overlay filter // leave videotoolbox in software since we use a software overlay filter
HardwareAccelerationMode.VideoToolbox => string.Empty, HardwareAccelerationMode.VideoToolbox => string.Empty,
// leave amf in software since we use a software overlay filter
HardwareAccelerationMode.Amf => string.Empty,
_ => "hwupload" _ => "hwupload"
}; };
+2 -1
View File
@@ -6,5 +6,6 @@ public enum HardwareAccelerationMode
Qsv = 1, Qsv = 1,
Nvenc = 2, Nvenc = 2,
Vaapi = 3, Vaapi = 3,
VideoToolbox = 4 VideoToolbox = 4,
Amf = 5
} }
@@ -0,0 +1,11 @@
namespace ErsatzTV.FFmpeg.Option.HardwareAcceleration;
public class AmfHardwareAccelerationOption : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-hwaccel", "dxva2" };
public override FrameState NextState(FrameState currentState) => currentState with
{
FrameDataLocation = FrameDataLocation.Software
};
}
@@ -14,6 +14,7 @@ public static class AvailableHardwareAccelerationOptions
HardwareAccelerationMode.Qsv => new QsvHardwareAccelerationOption(), HardwareAccelerationMode.Qsv => new QsvHardwareAccelerationOption(),
HardwareAccelerationMode.Vaapi => GetVaapiAcceleration(vaapiDevice, logger), HardwareAccelerationMode.Vaapi => GetVaapiAcceleration(vaapiDevice, logger),
HardwareAccelerationMode.VideoToolbox => new VideoToolboxHardwareAccelerationOption(), HardwareAccelerationMode.VideoToolbox => new VideoToolboxHardwareAccelerationOption(),
HardwareAccelerationMode.Amf => new AmfHardwareAccelerationOption(),
HardwareAccelerationMode.None => Option<IPipelineStep>.None, HardwareAccelerationMode.None => Option<IPipelineStep>.None,
_ => LogUnknownMode(mode, logger) _ => LogUnknownMode(mode, logger)
}; };
@@ -1,8 +1,10 @@
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Health; using ErsatzTV.Core.Health;
using ErsatzTV.Core.Health.Checks; using ErsatzTV.Core.Health.Checks;
using ErsatzTV.Core.Interfaces.Repositories; using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Runtime;
using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Data;
using LanguageExt.UnsafeValueAccess; using LanguageExt.UnsafeValueAccess;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@@ -12,14 +14,17 @@ namespace ErsatzTV.Infrastructure.Health.Checks;
public class HardwareAccelerationHealthCheck : BaseHealthCheck, IHardwareAccelerationHealthCheck public class HardwareAccelerationHealthCheck : BaseHealthCheck, IHardwareAccelerationHealthCheck
{ {
private readonly IConfigElementRepository _configElementRepository; private readonly IConfigElementRepository _configElementRepository;
private readonly IRuntimeInfo _runtimeInfo;
private readonly IDbContextFactory<TvContext> _dbContextFactory; private readonly IDbContextFactory<TvContext> _dbContextFactory;
public HardwareAccelerationHealthCheck( public HardwareAccelerationHealthCheck(
IDbContextFactory<TvContext> dbContextFactory, IDbContextFactory<TvContext> dbContextFactory,
IConfigElementRepository configElementRepository) IConfigElementRepository configElementRepository,
IRuntimeInfo runtimeInfo)
{ {
_dbContextFactory = dbContextFactory; _dbContextFactory = dbContextFactory;
_configElementRepository = configElementRepository; _configElementRepository = configElementRepository;
_runtimeInfo = runtimeInfo;
} }
public override string Title => "Hardware Acceleration"; public override string Title => "Hardware Acceleration";
@@ -91,7 +96,7 @@ public class HardwareAccelerationHealthCheck : BaseHealthCheck, IHardwareAcceler
return None; return None;
} }
private static async Task<List<HardwareAccelerationKind>> GetSupportedAccelerationKinds( private async Task<List<HardwareAccelerationKind>> GetSupportedAccelerationKinds(
string ffmpegPath, string ffmpegPath,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
@@ -120,6 +125,21 @@ public class HardwareAccelerationHealthCheck : BaseHealthCheck, IHardwareAcceler
} }
} }
if (_runtimeInfo.IsOSPlatform(OSPlatform.Windows))
{
string output2 = await GetProcessOutput(
ffmpegPath,
new[] { "-v", "quiet", "-encoders" },
cancellationToken);
foreach (string method in output2.Split("\n").Map(s => s.Trim()))
{
if (method.Contains("_amf "))
{
result.Add(HardwareAccelerationKind.Amf);
}
}
}
return result.ToList(); return result.ToList();
} }
} }
@@ -32,6 +32,12 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi
FFmpegProfileVideoFormat.Hevc FFmpegProfileVideoFormat.Hevc
}; };
private static readonly List<FFmpegProfileVideoFormat> AmfFormats = new()
{
FFmpegProfileVideoFormat.H264,
FFmpegProfileVideoFormat.Hevc
};
public FFmpegProfileEditViewModelValidator() public FFmpegProfileEditViewModelValidator()
{ {
RuleFor(x => x.Name).NotEmpty(); RuleFor(x => x.Name).NotEmpty();
@@ -76,5 +82,13 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi
RuleFor(x => x.VideoFormat).Must(c => VideoToolboxFormats.Contains(c)) RuleFor(x => x.VideoFormat).Must(c => VideoToolboxFormats.Contains(c))
.WithMessage("VideoToolbox supports formats (h264, hevc)"); .WithMessage("VideoToolbox supports formats (h264, hevc)");
}); });
When(
x => x.HardwareAcceleration == HardwareAccelerationKind.Amf,
() =>
{
RuleFor(x => x.VideoFormat).Must(c => AmfFormats.Contains(c))
.WithMessage("Amf supports formats (h264, hevc)");
});
} }
} }