Browse Source

add amf acceleration (#947)

pull/951/head
Jason Dove 3 years ago committed by GitHub
parent
commit
3972e3603b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 9
      ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs
  3. 3
      ErsatzTV.Core/Domain/HardwareAccelerationKind.cs
  4. 2
      ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs
  5. 1
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  6. 15
      ErsatzTV.FFmpeg/Encoder/Amf/EncoderH264Amf.cs
  7. 15
      ErsatzTV.FFmpeg/Encoder/Amf/EncoderHevcAmf.cs
  8. 8
      ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs
  9. 10
      ErsatzTV.FFmpeg/Filter/ComplexFilter.cs
  10. 3
      ErsatzTV.FFmpeg/Filter/SubtitleHardwareUploadFilter.cs
  11. 3
      ErsatzTV.FFmpeg/Filter/WatermarkHardwareUploadFilter.cs
  12. 3
      ErsatzTV.FFmpeg/HardwareAccelerationMode.cs
  13. 11
      ErsatzTV.FFmpeg/Option/HardwareAcceleration/AmfHardwareAccelerationOption.cs
  14. 1
      ErsatzTV.FFmpeg/Option/HardwareAcceleration/AvailableHardwareAccelerationOptions.cs
  15. 24
      ErsatzTV.Infrastructure/Health/Checks/HardwareAccelerationHealthCheck.cs
  16. 14
      ErsatzTV/Validators/FFmpegProfileEditViewModelValidator.cs

1
CHANGELOG.md

@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -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

9
ErsatzTV.Core.Tests/FFmpeg/TranscodingTests.cs

@ -168,6 +168,11 @@ public class TranscodingTests @@ -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 @@ -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")
{

3
ErsatzTV.Core/Domain/HardwareAccelerationKind.cs

@ -6,5 +6,6 @@ public enum HardwareAccelerationKind @@ -6,5 +6,6 @@ public enum HardwareAccelerationKind
Qsv = 1,
Nvenc = 2,
Vaapi = 3,
VideoToolbox = 4
VideoToolbox = 4,
Amf = 5
}

2
ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs

@ -169,6 +169,7 @@ public class FFmpegComplexFilterBuilder @@ -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 @@ -200,6 +201,7 @@ public class FFmpegComplexFilterBuilder
bool usesHardwareFilters = acceleration != HardwareAccelerationKind.None &&
acceleration != HardwareAccelerationKind.VideoToolbox &&
acceleration != HardwareAccelerationKind.Amf &&
!isHardwareDecode &&
(_deinterlace || _scaleToSize.IsSome);

1
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -627,6 +627,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -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
};
}

15
ErsatzTV.FFmpeg/Encoder/Amf/EncoderH264Amf.cs

@ -0,0 +1,15 @@ @@ -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
};
}

15
ErsatzTV.FFmpeg/Encoder/Amf/EncoderHevcAmf.cs

@ -0,0 +1,15 @@ @@ -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
};
}

8
ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs

@ -1,4 +1,5 @@ @@ -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;
@ -72,6 +73,13 @@ public static class AvailableEncoders @@ -72,6 +73,13 @@ public static class AvailableEncoders
(HardwareAccelerationMode.VideoToolbox, VideoFormat.H264) when hardwareCapabilities.CanEncode(
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(),

10
ErsatzTV.FFmpeg/Filter/ComplexFilter.cs

@ -173,7 +173,8 @@ public class ComplexFilter : IPipelineStep @@ -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 @@ -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

3
ErsatzTV.FFmpeg/Filter/SubtitleHardwareUploadFilter.cs

@ -25,6 +25,9 @@ public class SubtitleHardwareUploadFilter : BaseFilter @@ -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"
};

3
ErsatzTV.FFmpeg/Filter/WatermarkHardwareUploadFilter.cs

@ -24,6 +24,9 @@ public class WatermarkHardwareUploadFilter : BaseFilter @@ -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"
};

3
ErsatzTV.FFmpeg/HardwareAccelerationMode.cs

@ -6,5 +6,6 @@ public enum HardwareAccelerationMode @@ -6,5 +6,6 @@ public enum HardwareAccelerationMode
Qsv = 1,
Nvenc = 2,
Vaapi = 3,
VideoToolbox = 4
VideoToolbox = 4,
Amf = 5
}

11
ErsatzTV.FFmpeg/Option/HardwareAcceleration/AmfHardwareAccelerationOption.cs

@ -0,0 +1,11 @@ @@ -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
};
}

1
ErsatzTV.FFmpeg/Option/HardwareAcceleration/AvailableHardwareAccelerationOptions.cs

@ -14,6 +14,7 @@ public static class AvailableHardwareAccelerationOptions @@ -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)
};

24
ErsatzTV.Infrastructure/Health/Checks/HardwareAccelerationHealthCheck.cs

@ -1,8 +1,10 @@ @@ -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; @@ -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 @@ -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 @@ -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();
}
}

14
ErsatzTV/Validators/FFmpegProfileEditViewModelValidator.cs

@ -32,6 +32,12 @@ public class FFmpegProfileEditViewModelValidator : AbstractValidator<FFmpegProfi @@ -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 @@ -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)");
});
}
}

Loading…
Cancel
Save