mirror of https://github.com/ErsatzTV/ErsatzTV.git
Browse Source
* try to fix vaapi inconsistencies * log unexpected data * vaapi fixes * disable 444 test * add qsv deinterlace filter; qsv fixes * add videotoolbox accelerationpull/631/head
23 changed files with 293 additions and 67 deletions
@ -1,46 +1,69 @@
@@ -1,46 +1,69 @@
|
||||
using ErsatzTV.FFmpeg.Encoder.Nvenc; |
||||
using ErsatzTV.FFmpeg.Encoder.Qsv; |
||||
using ErsatzTV.FFmpeg.Encoder.Vaapi; |
||||
using ErsatzTV.FFmpeg.Encoder.VideoToolbox; |
||||
using ErsatzTV.FFmpeg.Format; |
||||
using Microsoft.Extensions.Logging; |
||||
using LanguageExt; |
||||
|
||||
namespace ErsatzTV.FFmpeg.Encoder; |
||||
|
||||
public static class AvailableEncoders |
||||
{ |
||||
public static IEncoder ForVideoFormat(FrameState currentState, FrameState desiredState) => |
||||
public static Option<IEncoder> ForVideoFormat(FrameState currentState, FrameState desiredState, ILogger logger) => |
||||
(desiredState.HardwareAccelerationMode, desiredState.VideoFormat) switch |
||||
{ |
||||
(HardwareAccelerationMode.Nvenc, VideoFormat.Hevc) => new EncoderHevcNvenc(), |
||||
(HardwareAccelerationMode.Nvenc, VideoFormat.H264) => new EncoderH264Nvenc(), |
||||
|
||||
(HardwareAccelerationMode.Qsv, VideoFormat.Hevc) => new EncoderHevcQsv(), |
||||
(HardwareAccelerationMode.Qsv, VideoFormat.H264) => new EncoderH264Qsv(), |
||||
(HardwareAccelerationMode.Qsv, VideoFormat.H264) => new EncoderH264Qsv(currentState), |
||||
|
||||
(HardwareAccelerationMode.Vaapi, VideoFormat.Hevc) => new EncoderHevcVaapi(currentState), |
||||
(HardwareAccelerationMode.Vaapi, VideoFormat.H264) => new EncoderH264Vaapi(currentState), |
||||
|
||||
(HardwareAccelerationMode.VideoToolbox, VideoFormat.Hevc) => new EncoderHevcVideoToolbox(), |
||||
(HardwareAccelerationMode.VideoToolbox, VideoFormat.H264) => new EncoderH264VideoToolbox(), |
||||
|
||||
(_, VideoFormat.Hevc) => new EncoderLibx265(), |
||||
(_, VideoFormat.H264) => new EncoderLibx264(), |
||||
(_, VideoFormat.Mpeg2Video) => new EncoderMpeg2Video(), |
||||
|
||||
(_, VideoFormat.Undetermined) => new EncoderImplicitVideo(), |
||||
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(desiredState.VideoFormat), desiredState.VideoFormat, null) |
||||
var (accel, videoFormat) => LogUnknownEncoder(accel, videoFormat, logger) |
||||
}; |
||||
|
||||
private static Option<IEncoder> LogUnknownEncoder( |
||||
HardwareAccelerationMode hardwareAccelerationMode, |
||||
string videoFormat, |
||||
ILogger logger) |
||||
{ |
||||
logger.LogWarning( |
||||
"Unable to determine video encoder for {AccelMode} - {VideoFormat}; may have playback issues", |
||||
hardwareAccelerationMode, |
||||
videoFormat); |
||||
return Option<IEncoder>.None; |
||||
} |
||||
|
||||
public static IEncoder ForAudioFormat(FrameState desiredState) |
||||
public static Option<IEncoder> ForAudioFormat(FrameState desiredState, ILogger logger) |
||||
{ |
||||
return desiredState.AudioFormat.Match( |
||||
audioFormat => |
||||
audioFormat switch |
||||
{ |
||||
AudioFormat.Aac => (IEncoder)new EncoderAac(), |
||||
AudioFormat.Aac => (Option<IEncoder>)new EncoderAac(), |
||||
AudioFormat.Ac3 => new EncoderAc3(), |
||||
_ => throw new ArgumentOutOfRangeException(nameof(audioFormat), audioFormat, null) |
||||
_ => LogUnknownEncoder(audioFormat, logger) |
||||
}, |
||||
() => throw new ArgumentOutOfRangeException( |
||||
nameof(desiredState.AudioFormat), |
||||
desiredState.AudioFormat, |
||||
null)); |
||||
() => LogUnknownEncoder(string.Empty, logger)); |
||||
} |
||||
|
||||
private static Option<IEncoder> LogUnknownEncoder( |
||||
string audioFormat, |
||||
ILogger logger) |
||||
{ |
||||
logger.LogWarning("Unable to determine audio encoder for {AudioFormat}; may have playback issues", audioFormat); |
||||
return Option<IEncoder>.None; |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
using ErsatzTV.FFmpeg.Format; |
||||
|
||||
namespace ErsatzTV.FFmpeg.Encoder.VideoToolbox; |
||||
|
||||
public class EncoderH264VideoToolbox : EncoderBase |
||||
{ |
||||
public override FrameState NextState(FrameState currentState) => currentState with |
||||
{ |
||||
VideoFormat = VideoFormat.H264, |
||||
FrameDataLocation = FrameDataLocation.Hardware |
||||
}; |
||||
|
||||
public override string Name => "h264_videotoolbox"; |
||||
public override StreamKind Kind => StreamKind.Video; |
||||
} |
||||
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
using ErsatzTV.FFmpeg.Format; |
||||
|
||||
namespace ErsatzTV.FFmpeg.Encoder.VideoToolbox; |
||||
|
||||
public class EncoderHevcVideoToolbox : EncoderBase |
||||
{ |
||||
public override FrameState NextState(FrameState currentState) => currentState with |
||||
{ |
||||
VideoFormat = VideoFormat.Hevc, |
||||
FrameDataLocation = FrameDataLocation.Hardware |
||||
}; |
||||
|
||||
public override string Name => "hevc_videotoolbox"; |
||||
public override StreamKind Kind => StreamKind.Video; |
||||
} |
||||
@ -0,0 +1,41 @@
@@ -0,0 +1,41 @@
|
||||
using ErsatzTV.FFmpeg.Format; |
||||
|
||||
namespace ErsatzTV.FFmpeg.Filter.Qsv; |
||||
|
||||
public class DeinterlaceQsvFilter : BaseFilter |
||||
{ |
||||
private readonly FrameState _currentState; |
||||
|
||||
public DeinterlaceQsvFilter(FrameState currentState) |
||||
{ |
||||
_currentState = currentState; |
||||
} |
||||
|
||||
// deinterlace_qsv seems to only support nv12, not p010le
|
||||
public override string Filter => _currentState.FrameDataLocation == FrameDataLocation.Software |
||||
? "format=nv12,hwupload=extra_hw_frames=64,deinterlace_qsv" |
||||
: "deinterlace_qsv"; |
||||
|
||||
public override FrameState NextState(FrameState currentState) |
||||
{ |
||||
FrameState result = currentState with |
||||
{ |
||||
Deinterlaced = true, |
||||
FrameDataLocation = FrameDataLocation.Hardware |
||||
}; |
||||
|
||||
// deinterlace_qsv seems to only support nv12, not p010le
|
||||
foreach (IPixelFormat pixelFormat in currentState.PixelFormat) |
||||
{ |
||||
if (pixelFormat.FFmpegName != FFmpegFormat.NV12) |
||||
{ |
||||
result = result with |
||||
{ |
||||
PixelFormat = new PixelFormatNv12(pixelFormat.Name) |
||||
}; |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
} |
||||
@ -1,15 +1,41 @@
@@ -1,15 +1,41 @@
|
||||
namespace ErsatzTV.FFmpeg.Option.HardwareAcceleration; |
||||
using ErsatzTV.FFmpeg.Format; |
||||
|
||||
namespace ErsatzTV.FFmpeg.Option.HardwareAcceleration; |
||||
|
||||
public class QsvHardwareAccelerationOption : GlobalOption |
||||
{ |
||||
// TODO: read this from ffmpeg output
|
||||
private readonly List<string> _supportedFFmpegFormats = new() |
||||
{ |
||||
FFmpegFormat.NV12, |
||||
FFmpegFormat.P010LE |
||||
}; |
||||
|
||||
public override IList<string> GlobalOptions => new List<string> |
||||
{ |
||||
"-hwaccel", "qsv", |
||||
"-init_hw_device", "qsv=qsv:MFX_IMPL_hw_any" |
||||
}; |
||||
|
||||
public override FrameState NextState(FrameState currentState) => currentState with |
||||
// qsv encoders want nv12
|
||||
public override FrameState NextState(FrameState currentState) |
||||
{ |
||||
HardwareAccelerationMode = HardwareAccelerationMode.Qsv |
||||
}; |
||||
FrameState result = currentState with { HardwareAccelerationMode = HardwareAccelerationMode.Qsv }; |
||||
|
||||
foreach (IPixelFormat pixelFormat in currentState.PixelFormat) |
||||
{ |
||||
if (_supportedFFmpegFormats.Contains(pixelFormat.FFmpegName)) |
||||
{ |
||||
return result; |
||||
} |
||||
|
||||
return currentState with { PixelFormat = new PixelFormatNv12(pixelFormat.Name) }; |
||||
} |
||||
|
||||
return currentState with |
||||
{ |
||||
HardwareAccelerationMode = HardwareAccelerationMode.Qsv, |
||||
PixelFormat = new PixelFormatNv12(new PixelFormatUnknown().Name) |
||||
}; |
||||
} |
||||
} |
||||
|
||||
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
namespace ErsatzTV.FFmpeg.Option.HardwareAcceleration; |
||||
|
||||
public class VideoToolboxHardwareAccelerationOption : GlobalOption |
||||
{ |
||||
public override IList<string> GlobalOptions => new List<string> { "-hwaccel", "videotoolbox" }; |
||||
|
||||
public override FrameState NextState(FrameState currentState) => currentState with |
||||
{ |
||||
HardwareAccelerationMode = HardwareAccelerationMode.VideoToolbox |
||||
}; |
||||
} |
||||
Loading…
Reference in new issue