mirror of https://github.com/ErsatzTV/ErsatzTV.git
5 changed files with 154 additions and 4 deletions
@ -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 |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue