add amf pipeline (#1048)
This commit is contained in:
@@ -212,11 +212,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))] HardwareAccelerationKind profileAcceleration)
|
// [ValueSource(typeof(TestData), nameof(TestData.NvidiaAcceleration))] 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)
|
[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")
|
||||||
{
|
{
|
||||||
@@ -328,7 +328,10 @@ public class TranscodingTests
|
|||||||
new Mock<ITempFilePool>().Object,
|
new Mock<ITempFilePool>().Object,
|
||||||
new PipelineBuilderFactory(
|
new PipelineBuilderFactory(
|
||||||
new RuntimeInfo(),
|
new RuntimeInfo(),
|
||||||
new FakeNvidiaCapabilitiesFactory(),
|
//new FakeNvidiaCapabilitiesFactory(),
|
||||||
|
new HardwareCapabilitiesFactory(
|
||||||
|
new MemoryCache(new MemoryCacheOptions()),
|
||||||
|
LoggerFactory.CreateLogger<HardwareCapabilitiesFactory>()),
|
||||||
LoggerFactory.CreateLogger<PipelineBuilderFactory>()),
|
LoggerFactory.CreateLogger<PipelineBuilderFactory>()),
|
||||||
LoggerFactory.CreateLogger<FFmpegLibraryProcessService>());
|
LoggerFactory.CreateLogger<FFmpegLibraryProcessService>());
|
||||||
|
|
||||||
@@ -697,7 +700,11 @@ public class TranscodingTests
|
|||||||
videoStream.ColorTransfer,
|
videoStream.ColorTransfer,
|
||||||
videoStream.ColorPrimaries);
|
videoStream.ColorPrimaries);
|
||||||
|
|
||||||
colorParams.IsBt709.Should().BeTrue($"{colorParams}");
|
// AMF doesn't seem to set this metadata properly
|
||||||
|
if (profileAcceleration != HardwareAccelerationKind.Amf)
|
||||||
|
{
|
||||||
|
colorParams.IsBt709.Should().BeTrue($"{colorParams}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
using ErsatzTV.FFmpeg.Format;
|
||||||
|
|
||||||
|
namespace ErsatzTV.FFmpeg.Capabilities;
|
||||||
|
|
||||||
|
public class AmfHardwareCapabilities : IHardwareCapabilities
|
||||||
|
{
|
||||||
|
public bool CanDecode(string videoFormat, Option<IPixelFormat> maybePixelFormat) => false;
|
||||||
|
|
||||||
|
public bool CanEncode(string videoFormat, Option<IPixelFormat> maybePixelFormat)
|
||||||
|
{
|
||||||
|
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8);
|
||||||
|
|
||||||
|
return (videoFormat, bitDepth) switch
|
||||||
|
{
|
||||||
|
// 10-bit hevc encoding is not yet supported by ffmpeg
|
||||||
|
(VideoFormat.Hevc, 10) => false,
|
||||||
|
|
||||||
|
// 10-bit h264 encoding is not support by any hardware
|
||||||
|
(VideoFormat.H264, 10) => false,
|
||||||
|
|
||||||
|
_ => true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
|
|||||||
hardwareAccelerationMode switch
|
hardwareAccelerationMode switch
|
||||||
{
|
{
|
||||||
HardwareAccelerationMode.Nvenc => await GetNvidiaCapabilities(ffmpegPath),
|
HardwareAccelerationMode.Nvenc => await GetNvidiaCapabilities(ffmpegPath),
|
||||||
|
HardwareAccelerationMode.Amf => new AmfHardwareCapabilities(),
|
||||||
_ => new DefaultHardwareCapabilities()
|
_ => new DefaultHardwareCapabilities()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
using ErsatzTV.FFmpeg.Capabilities;
|
||||||
|
using ErsatzTV.FFmpeg.Encoder;
|
||||||
|
using ErsatzTV.FFmpeg.Encoder.Amf;
|
||||||
|
using ErsatzTV.FFmpeg.Filter;
|
||||||
|
using ErsatzTV.FFmpeg.Format;
|
||||||
|
using ErsatzTV.FFmpeg.Option;
|
||||||
|
using ErsatzTV.FFmpeg.Option.HardwareAcceleration;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace ErsatzTV.FFmpeg.Pipeline;
|
||||||
|
|
||||||
|
public class AmfPipelineBuilder : SoftwarePipelineBuilder
|
||||||
|
{
|
||||||
|
private readonly IHardwareCapabilities _hardwareCapabilities;
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
|
||||||
|
public AmfPipelineBuilder(
|
||||||
|
IHardwareCapabilities hardwareCapabilities,
|
||||||
|
HardwareAccelerationMode hardwareAccelerationMode,
|
||||||
|
Option<VideoInputFile> videoInputFile,
|
||||||
|
Option<AudioInputFile> audioInputFile,
|
||||||
|
Option<WatermarkInputFile> watermarkInputFile,
|
||||||
|
Option<SubtitleInputFile> subtitleInputFile,
|
||||||
|
string reportsFolder,
|
||||||
|
string fontsFolder,
|
||||||
|
ILogger logger) : base(
|
||||||
|
hardwareAccelerationMode,
|
||||||
|
videoInputFile,
|
||||||
|
audioInputFile,
|
||||||
|
watermarkInputFile,
|
||||||
|
subtitleInputFile,
|
||||||
|
reportsFolder,
|
||||||
|
fontsFolder,
|
||||||
|
logger)
|
||||||
|
{
|
||||||
|
_hardwareCapabilities = hardwareCapabilities;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override FFmpegState SetAccelState(
|
||||||
|
VideoStream videoStream,
|
||||||
|
FFmpegState ffmpegState,
|
||||||
|
FrameState desiredState,
|
||||||
|
PipelineContext context,
|
||||||
|
ICollection<IPipelineStep> pipelineSteps)
|
||||||
|
{
|
||||||
|
bool canDecode = _hardwareCapabilities.CanDecode(videoStream.Codec, videoStream.PixelFormat);
|
||||||
|
bool canEncode = _hardwareCapabilities.CanEncode(desiredState.VideoFormat, desiredState.PixelFormat);
|
||||||
|
|
||||||
|
pipelineSteps.Add(new AmfHardwareAccelerationOption());
|
||||||
|
|
||||||
|
// disable hw accel if decoder/encoder isn't supported
|
||||||
|
return ffmpegState with
|
||||||
|
{
|
||||||
|
DecoderHardwareAccelerationMode = canDecode
|
||||||
|
? HardwareAccelerationMode.Amf
|
||||||
|
: HardwareAccelerationMode.None,
|
||||||
|
EncoderHardwareAccelerationMode = canEncode
|
||||||
|
? HardwareAccelerationMode.Amf
|
||||||
|
: HardwareAccelerationMode.None
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Option<IEncoder> GetEncoder(FFmpegState ffmpegState, FrameState currentState, FrameState desiredState)
|
||||||
|
{
|
||||||
|
return (ffmpegState.EncoderHardwareAccelerationMode, desiredState.VideoFormat) switch
|
||||||
|
{
|
||||||
|
(HardwareAccelerationMode.Amf, VideoFormat.Hevc) =>
|
||||||
|
new EncoderHevcAmf(),
|
||||||
|
(HardwareAccelerationMode.Amf, VideoFormat.H264) =>
|
||||||
|
new EncoderH264Amf(),
|
||||||
|
|
||||||
|
_ => GetSoftwareEncoder(currentState, desiredState)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override List<IPipelineFilterStep> SetPixelFormat(
|
||||||
|
VideoStream videoStream,
|
||||||
|
Option<IPixelFormat> desiredPixelFormat,
|
||||||
|
FrameState currentState,
|
||||||
|
ICollection<IPipelineStep> pipelineSteps)
|
||||||
|
{
|
||||||
|
var result = new List<IPipelineFilterStep>();
|
||||||
|
|
||||||
|
foreach (IPixelFormat pixelFormat in desiredPixelFormat)
|
||||||
|
{
|
||||||
|
if (!videoStream.ColorParams.IsBt709)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Adding colorspace filter");
|
||||||
|
var colorspace = new ColorspaceFilter(videoStream, pixelFormat);
|
||||||
|
currentState = colorspace.NextState(currentState);
|
||||||
|
result.Add(colorspace);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentState.PixelFormat.Map(f => f.FFmpegName) != pixelFormat.FFmpegName)
|
||||||
|
{
|
||||||
|
_logger.LogDebug(
|
||||||
|
"Format {A} doesn't equal {B}",
|
||||||
|
currentState.PixelFormat.Map(f => f.FFmpegName),
|
||||||
|
pixelFormat.FFmpegName);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipelineSteps.Add(new PixelFormatOutputOption(pixelFormat));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -70,6 +70,16 @@ public class PipelineBuilderFactory : IPipelineBuilderFactory
|
|||||||
reportsFolder,
|
reportsFolder,
|
||||||
fontsFolder,
|
fontsFolder,
|
||||||
_logger),
|
_logger),
|
||||||
|
HardwareAccelerationMode.Amf => new AmfPipelineBuilder(
|
||||||
|
await _hardwareCapabilitiesFactory.GetHardwareCapabilities(ffmpegPath, hardwareAccelerationMode),
|
||||||
|
hardwareAccelerationMode,
|
||||||
|
videoInputFile,
|
||||||
|
audioInputFile,
|
||||||
|
watermarkInputFile,
|
||||||
|
subtitleInputFile,
|
||||||
|
reportsFolder,
|
||||||
|
fontsFolder,
|
||||||
|
_logger),
|
||||||
_ => new SoftwarePipelineBuilder(
|
_ => new SoftwarePipelineBuilder(
|
||||||
hardwareAccelerationMode,
|
hardwareAccelerationMode,
|
||||||
videoInputFile,
|
videoInputFile,
|
||||||
|
|||||||
Reference in New Issue
Block a user