|
|
|
@ -4,18 +4,13 @@ using Microsoft.Extensions.Logging; |
|
|
|
|
|
|
|
|
|
|
|
namespace ErsatzTV.FFmpeg.Capabilities; |
|
|
|
namespace ErsatzTV.FFmpeg.Capabilities; |
|
|
|
|
|
|
|
|
|
|
|
public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
public class VaapiHardwareCapabilities( |
|
|
|
|
|
|
|
List<VaapiProfileEntrypoint> profileEntrypoints, |
|
|
|
|
|
|
|
string generation, |
|
|
|
|
|
|
|
ILogger logger) |
|
|
|
|
|
|
|
: IHardwareCapabilities |
|
|
|
{ |
|
|
|
{ |
|
|
|
private readonly ILogger _logger; |
|
|
|
public int EntrypointCount => profileEntrypoints.Count; |
|
|
|
private readonly List<VaapiProfileEntrypoint> _profileEntrypoints; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public VaapiHardwareCapabilities(List<VaapiProfileEntrypoint> profileEntrypoints, ILogger logger) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
_profileEntrypoints = profileEntrypoints; |
|
|
|
|
|
|
|
_logger = logger; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public int EntrypointCount => _profileEntrypoints.Count; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public FFmpegCapability CanDecode( |
|
|
|
public FFmpegCapability CanDecode( |
|
|
|
string videoFormat, |
|
|
|
string videoFormat, |
|
|
|
@ -25,121 +20,126 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
{ |
|
|
|
{ |
|
|
|
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8); |
|
|
|
int bitDepth = maybePixelFormat.Map(pf => pf.BitDepth).IfNone(8); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool isPolaris = generation.Contains("polaris", StringComparison.OrdinalIgnoreCase); |
|
|
|
|
|
|
|
|
|
|
|
bool isHardware = (videoFormat, videoProfile.IfNone(string.Empty).ToLowerInvariant()) switch |
|
|
|
bool isHardware = (videoFormat, videoProfile.IfNone(string.Empty).ToLowerInvariant()) switch |
|
|
|
{ |
|
|
|
{ |
|
|
|
// no hardware decoding of 10-bit h264
|
|
|
|
// no hardware decoding of 10-bit h264
|
|
|
|
(VideoFormat.H264, _) when bitDepth == 10 => false, |
|
|
|
(VideoFormat.H264, _) when bitDepth == 10 => false, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// skip polaris hardware decoding 10-bit
|
|
|
|
|
|
|
|
(_, _) when bitDepth == 10 && isPolaris => false, |
|
|
|
|
|
|
|
|
|
|
|
// no hardware decoding of h264 baseline profile
|
|
|
|
// no hardware decoding of h264 baseline profile
|
|
|
|
(VideoFormat.H264, "baseline" or "66") => false, |
|
|
|
(VideoFormat.H264, "baseline" or "66") => false, |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.H264, "main" or "77") => |
|
|
|
(VideoFormat.H264, "main" or "77") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.H264Main, |
|
|
|
VaapiProfile: VaapiProfile.H264Main, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.H264, "high" or "100") => |
|
|
|
(VideoFormat.H264, "high" or "100") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.H264High, |
|
|
|
VaapiProfile: VaapiProfile.H264High, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.H264, "high 10" or "110") => |
|
|
|
(VideoFormat.H264, "high 10" or "110") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.H264High, |
|
|
|
VaapiProfile: VaapiProfile.H264High, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.H264, "baseline constrained" or "constrained baseline" or "578") => |
|
|
|
(VideoFormat.H264, "baseline constrained" or "constrained baseline" or "578") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.H264ConstrainedBaseline, |
|
|
|
VaapiProfile: VaapiProfile.H264ConstrainedBaseline, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Mpeg2Video, "main" or "4") => |
|
|
|
(VideoFormat.Mpeg2Video, "main" or "4") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Main, |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Main, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Mpeg2Video, "simple" or "5") => |
|
|
|
(VideoFormat.Mpeg2Video, "simple" or "5") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Simple, |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Simple, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Vc1, "simple" or "0") => |
|
|
|
(VideoFormat.Vc1, "simple" or "0") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Vc1Simple, |
|
|
|
VaapiProfile: VaapiProfile.Vc1Simple, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Vc1, "main" or "1") => |
|
|
|
(VideoFormat.Vc1, "main" or "1") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Vc1Main, |
|
|
|
VaapiProfile: VaapiProfile.Vc1Main, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Vc1, "advanced" or "3") => |
|
|
|
(VideoFormat.Vc1, "advanced" or "3") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Vc1Advanced, |
|
|
|
VaapiProfile: VaapiProfile.Vc1Advanced, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Hevc, "main" or "1") => |
|
|
|
(VideoFormat.Hevc, "main" or "1") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.HevcMain, |
|
|
|
VaapiProfile: VaapiProfile.HevcMain, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Hevc, "main 10" or "2") => |
|
|
|
(VideoFormat.Hevc, "main 10" or "2") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.HevcMain10, |
|
|
|
VaapiProfile: VaapiProfile.HevcMain10, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Vp9, "profile 0" or "0") => |
|
|
|
(VideoFormat.Vp9, "profile 0" or "0") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile0, |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile0, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Vp9, "profile 1" or "1") => |
|
|
|
(VideoFormat.Vp9, "profile 1" or "1") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile1, |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile1, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Vp9, "profile 2" or "2") => |
|
|
|
(VideoFormat.Vp9, "profile 2" or "2") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile2, |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile2, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Vp9, "profile 3" or "3") => |
|
|
|
(VideoFormat.Vp9, "profile 3" or "3") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile3, |
|
|
|
VaapiProfile: VaapiProfile.Vp9Profile3, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
(VideoFormat.Av1, "main" or "0") => |
|
|
|
(VideoFormat.Av1, "main" or "0") => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Av1Profile0, |
|
|
|
VaapiProfile: VaapiProfile.Av1Profile0, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Decode |
|
|
|
@ -151,7 +151,7 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
|
|
|
|
|
|
|
|
if (!isHardware) |
|
|
|
if (!isHardware) |
|
|
|
{ |
|
|
|
{ |
|
|
|
_logger.LogDebug( |
|
|
|
logger.LogDebug( |
|
|
|
"VAAPI does not support decoding {Format}/{Profile}, will use software decoder", |
|
|
|
"VAAPI does not support decoding {Format}/{Profile}, will use software decoder", |
|
|
|
videoFormat, |
|
|
|
videoFormat, |
|
|
|
videoProfile); |
|
|
|
videoProfile); |
|
|
|
@ -173,35 +173,35 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
VideoFormat.H264 when bitDepth == 10 => false, |
|
|
|
VideoFormat.H264 when bitDepth == 10 => false, |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.H264 => |
|
|
|
VideoFormat.H264 => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.H264Main, |
|
|
|
VaapiProfile: VaapiProfile.H264Main, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.Hevc when bitDepth == 10 => |
|
|
|
VideoFormat.Hevc when bitDepth == 10 => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.HevcMain10, |
|
|
|
VaapiProfile: VaapiProfile.HevcMain10, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.Hevc => |
|
|
|
VideoFormat.Hevc => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.HevcMain, |
|
|
|
VaapiProfile: VaapiProfile.HevcMain, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.Av1 => |
|
|
|
VideoFormat.Av1 => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Av1Profile0, |
|
|
|
VaapiProfile: VaapiProfile.Av1Profile0, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
}), |
|
|
|
}), |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.Mpeg2Video => |
|
|
|
VideoFormat.Mpeg2Video => |
|
|
|
_profileEntrypoints.Any(e => e is |
|
|
|
profileEntrypoints.Any(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Main, |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Main, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
@ -212,7 +212,7 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
|
|
|
|
|
|
|
|
if (!isHardware) |
|
|
|
if (!isHardware) |
|
|
|
{ |
|
|
|
{ |
|
|
|
_logger.LogDebug( |
|
|
|
logger.LogDebug( |
|
|
|
"VAAPI does not support encoding {Format} with bit depth {BitDepth}, will use software encoder", |
|
|
|
"VAAPI does not support encoding {Format} with bit depth {BitDepth}, will use software encoder", |
|
|
|
videoFormat, |
|
|
|
videoFormat, |
|
|
|
bitDepth); |
|
|
|
bitDepth); |
|
|
|
@ -230,7 +230,7 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
VideoFormat.H264 when bitDepth == 10 => None, |
|
|
|
VideoFormat.H264 when bitDepth == 10 => None, |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.H264 => |
|
|
|
VideoFormat.H264 => |
|
|
|
_profileEntrypoints.Where(e => e is |
|
|
|
profileEntrypoints.Where(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.H264Main, |
|
|
|
VaapiProfile: VaapiProfile.H264Main, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
@ -238,7 +238,7 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
.HeadOrNone(), |
|
|
|
.HeadOrNone(), |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.Hevc when bitDepth == 10 => |
|
|
|
VideoFormat.Hevc when bitDepth == 10 => |
|
|
|
_profileEntrypoints.Where(e => e is |
|
|
|
profileEntrypoints.Where(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.HevcMain10, |
|
|
|
VaapiProfile: VaapiProfile.HevcMain10, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
@ -246,7 +246,7 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
.HeadOrNone(), |
|
|
|
.HeadOrNone(), |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.Hevc => |
|
|
|
VideoFormat.Hevc => |
|
|
|
_profileEntrypoints.Where(e => e is |
|
|
|
profileEntrypoints.Where(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.HevcMain, |
|
|
|
VaapiProfile: VaapiProfile.HevcMain, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
@ -254,7 +254,7 @@ public class VaapiHardwareCapabilities : IHardwareCapabilities |
|
|
|
.HeadOrNone(), |
|
|
|
.HeadOrNone(), |
|
|
|
|
|
|
|
|
|
|
|
VideoFormat.Mpeg2Video => |
|
|
|
VideoFormat.Mpeg2Video => |
|
|
|
_profileEntrypoints.Where(e => e is |
|
|
|
profileEntrypoints.Where(e => e is |
|
|
|
{ |
|
|
|
{ |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Main, |
|
|
|
VaapiProfile: VaapiProfile.Mpeg2Main, |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
VaapiEntrypoint: VaapiEntrypoint.Encode or VaapiEntrypoint.EncodeLowPower |
|
|
|
|