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
- 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
- Add `Amf` hardware acceleration option for AMD GPUs on Windows
## [0.6.6-beta] - 2022-08-17
### Fixed
@@ -168,6 +168,11 @@ public class TranscodingTests
HardwareAccelerationKind.VideoToolbox
};
public static HardwareAccelerationKind[] AmfAcceleration =
{
HardwareAccelerationKind.Amf
};
public static HardwareAccelerationKind[] QsvAcceleration =
{
HardwareAccelerationKind.Qsv
@@ -192,11 +197,11 @@ public class TranscodingTests
[ValueSource(typeof(TestData), nameof(TestData.VideoFormats))]
FFmpegProfileVideoFormat profileVideoFormat,
// [ValueSource(typeof(TestData), nameof(TestData.NoAcceleration))] HardwareAccelerationKind profileAcceleration)
[ValueSource(typeof(TestData), nameof(TestData.NvidiaAcceleration))]
HardwareAccelerationKind profileAcceleration)
// [ValueSource(typeof(TestData), nameof(TestData.NvidiaAcceleration))] HardwareAccelerationKind profileAcceleration)
// [ValueSource(typeof(TestData), nameof(TestData.VaapiAcceleration))] HardwareAccelerationKind profileAcceleration)
// [ValueSource(typeof(TestData), nameof(TestData.QsvAcceleration))] 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")
{
@@ -6,5 +6,6 @@ public enum HardwareAccelerationKind
Qsv = 1,
Nvenc = 2,
Vaapi = 3,
VideoToolbox = 4
VideoToolbox = 4,
Amf = 5
}
@@ -169,6 +169,7 @@ public class FFmpegComplexFilterBuilder
_videoDecoder.Contains("cuvid")),
HardwareAccelerationKind.Qsv => !isSong,
HardwareAccelerationKind.VideoToolbox => false,
HardwareAccelerationKind.Amf => false,
_ => false
};
@@ -200,6 +201,7 @@ public class FFmpegComplexFilterBuilder
bool usesHardwareFilters = acceleration != HardwareAccelerationKind.None &&
acceleration != HardwareAccelerationKind.VideoToolbox &&
acceleration != HardwareAccelerationKind.Amf &&
!isHardwareDecode &&
(_deinterlace || _scaleToSize.IsSome);
@@ -627,6 +627,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
HardwareAccelerationKind.Qsv => HardwareAccelerationMode.Qsv,
HardwareAccelerationKind.Vaapi => HardwareAccelerationMode.Vaapi,
HardwareAccelerationKind.VideoToolbox => HardwareAccelerationMode.VideoToolbox,
HardwareAccelerationKind.Amf => HardwareAccelerationMode.Amf,
_ => 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.Encoder.Amf;
using ErsatzTV.FFmpeg.Encoder.Nvenc;
using ErsatzTV.FFmpeg.Encoder.Qsv;
using ErsatzTV.FFmpeg.Encoder.Vaapi;
@@ -73,6 +74,13 @@ public static class AvailableEncoders
VideoFormat.H264,
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.H264) => new EncoderLibx264(),
(_, VideoFormat.Mpeg2Video) => new EncoderMpeg2Video(),
+5 -5
View File
@@ -173,7 +173,8 @@ public class ComplexFilter : IPipelineStep
if (_maybeSubtitleInputFile.Map(s => !s.IsImageBased).IfNone(false) &&
_ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Vaapi &&
_ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.VideoToolbox)
_ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.VideoToolbox &&
_ffmpegState.EncoderHardwareAccelerationMode != HardwareAccelerationMode.Amf)
{
uploadDownloadFilter = new HardwareDownloadFilter(_currentState).Filter;
}
@@ -230,10 +231,9 @@ public class ComplexFilter : IPipelineStep
if (filter != string.Empty)
{
string tempVideoLabel = string.IsNullOrWhiteSpace(videoFilterComplex) &&
string.IsNullOrWhiteSpace(watermarkFilterComplex)
? $"[{videoLabel}]"
: videoLabel;
string tempVideoLabel = videoLabel.StartsWith('[') && videoLabel.EndsWith(']')
? videoLabel
: $"[{videoLabel}]";
// vaapi uses software overlay and needs to upload
// 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
HardwareAccelerationMode.VideoToolbox => string.Empty,
// leave amf in software since we use a software overlay filter
HardwareAccelerationMode.Amf => string.Empty,
_ => "hwupload"
};
@@ -24,6 +24,9 @@ public class WatermarkHardwareUploadFilter : BaseFilter
// leave videotoolbox in software since we use a software overlay filter
HardwareAccelerationMode.VideoToolbox => string.Empty,
// leave amf in software since we use a software overlay filter
HardwareAccelerationMode.Amf => string.Empty,
_ => "hwupload"
};
+2 -1
View File
@@ -6,5 +6,6 @@ public enum HardwareAccelerationMode
Qsv = 1,
Nvenc = 2,
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.Vaapi => GetVaapiAcceleration(vaapiDevice, logger),
HardwareAccelerationMode.VideoToolbox => new VideoToolboxHardwareAccelerationOption(),
HardwareAccelerationMode.Amf => new AmfHardwareAccelerationOption(),
HardwareAccelerationMode.None => Option<IPipelineStep>.None,
_ => LogUnknownMode(mode, logger)
};
@@ -1,8 +1,10 @@
using System.Reflection;
using System.Runtime.InteropServices;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Health;
using ErsatzTV.Core.Health.Checks;
using ErsatzTV.Core.Interfaces.Repositories;
using ErsatzTV.Core.Interfaces.Runtime;
using ErsatzTV.Infrastructure.Data;
using LanguageExt.UnsafeValueAccess;
using Microsoft.EntityFrameworkCore;
@@ -12,14 +14,17 @@ namespace ErsatzTV.Infrastructure.Health.Checks;
public class HardwareAccelerationHealthCheck : BaseHealthCheck, IHardwareAccelerationHealthCheck
{
private readonly IConfigElementRepository _configElementRepository;
private readonly IRuntimeInfo _runtimeInfo;
private readonly IDbContextFactory<TvContext> _dbContextFactory;
public HardwareAccelerationHealthCheck(
IDbContextFactory<TvContext> dbContextFactory,
IConfigElementRepository configElementRepository)
IConfigElementRepository configElementRepository,
IRuntimeInfo runtimeInfo)
{
_dbContextFactory = dbContextFactory;
_configElementRepository = configElementRepository;
_runtimeInfo = runtimeInfo;
}
public override string Title => "Hardware Acceleration";
@@ -91,7 +96,7 @@ public class HardwareAccelerationHealthCheck : BaseHealthCheck, IHardwareAcceler
return None;
}
private static async Task<List<HardwareAccelerationKind>> GetSupportedAccelerationKinds(
private async Task<List<HardwareAccelerationKind>> GetSupportedAccelerationKinds(
string ffmpegPath,
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();
}
}
@@ -32,6 +32,12 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi
FFmpegProfileVideoFormat.Hevc
};
private static readonly List<FFmpegProfileVideoFormat> AmfFormats = new()
{
FFmpegProfileVideoFormat.H264,
FFmpegProfileVideoFormat.Hevc
};
public FFmpegProfileEditViewModelValidator()
{
RuleFor(x => x.Name).NotEmpty();
@@ -76,5 +82,13 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi
RuleFor(x => x.VideoFormat).Must(c => VideoToolboxFormats.Contains(c))
.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)");
});
}
}