add amf acceleration (#947)
This commit is contained in:
@@ -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(),
|
||||
|
||||
@@ -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"
|
||||
};
|
||||
|
||||
|
||||
@@ -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)");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user