Browse Source

fix 10-bit decoding with amd polaris (#2653)

* fix color conversion on amd polaris

* try software decode for polaris

* update changelog
pull/2654/head
Jason Dove 1 month ago committed by GitHub
parent
commit
bd7fd8984c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 24
      ErsatzTV.FFmpeg.Tests/Capabilities/Vaapi/VaapiCapabilityParserTests.cs
  3. 26
      ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs
  4. 43
      ErsatzTV.FFmpeg/Capabilities/Vaapi/VaapiCapabilityParser.cs
  5. 76
      ErsatzTV.FFmpeg/Capabilities/VaapiHardwareCapabilities.cs
  6. 2
      ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

1
CHANGELOG.md

@ -83,6 +83,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Add toggle to hide/show disabled channels in channel list - Add toggle to hide/show disabled channels in channel list
- Add disabled text color and `(D)` and `(H)` labels for disabled and hidden channels in channel list - Add disabled text color and `(D)` and `(H)` labels for disabled and hidden channels in channel list
- Graphics engine: fix subtitle path escaping and font loading - Graphics engine: fix subtitle path escaping and font loading
- Fix corrupt output (green artifacts) when decoding 10-bit content using AMD Polaris GPUs
### Changed ### Changed
- Classic schedules: `Refresh` classic playouts from playout list; do not `Reset` them - Classic schedules: `Refresh` classic playouts from playout list; do not `Reset` them

24
ErsatzTV.FFmpeg.Tests/Capabilities/Vaapi/VaapiCapabilityParserTests.cs

@ -9,6 +9,16 @@ namespace ErsatzTV.FFmpeg.Tests.Capabilities.Vaapi;
[TestFixture] [TestFixture]
public class VaapiCapabilityParserTests public class VaapiCapabilityParserTests
{ {
private const string GenerationPolarisOutput = @"Trying display: drm
vainfo: VA-API version: 1.22 (libva 2.22.0)
vainfo: Driver version: Mesa Gallium driver 25.2.7-arch1.1 for AMD Radeon RX 550 / 550 Series (radeonsi, polaris12, ACO, DRM 3.64, 6.17.8-arch1-1)
vainfo: Supported config attributes per profile/entrypoint pair
VAProfileMPEG2Simple/VAEntrypointVLD
VAConfigAttribRTFormat : VA_RT_FORMAT_YUV420
VAConfigAttribMaxPictureWidth : 1920
VAConfigAttribMaxPictureHeight : 1088
";
private const string BriefOutput = @"Trying display: wayland private const string BriefOutput = @"Trying display: wayland
vainfo: VA-API version: 1.18 (libva 2.18.2) vainfo: VA-API version: 1.18 (libva 2.18.2)
vainfo: Driver version: Mesa Gallium driver 23.1.2 for AMD Radeon RX 6750 XT (navi22, LLVM 15.0.7, DRM 3.52, 6.3.8-arch1-1) vainfo: Driver version: Mesa Gallium driver 23.1.2 for AMD Radeon RX 6750 XT (navi22, LLVM 15.0.7, DRM 3.52, 6.3.8-arch1-1)
@ -201,4 +211,18 @@ VAProfileNone/VAEntrypointVideoProc
entrypoint.RateControlModes.Count.ShouldBeGreaterThan(0); entrypoint.RateControlModes.Count.ShouldBeGreaterThan(0);
} }
} }
[Test]
public void Full_ShouldParseGeneration()
{
string generation = VaapiCapabilityParser.ParseGeneration(FullOutput);
generation.ShouldBe("navi22");
}
[Test]
public void Polaris_ShouldParseGeneration()
{
string generation = VaapiCapabilityParser.ParseGeneration(GenerationPolarisOutput);
generation.ShouldBe("polaris12");
}
} }

26
ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs

@ -29,6 +29,9 @@ public partial class HardwareCapabilitiesFactory(
private static readonly CompositeFormat VaapiCacheKeyFormat = private static readonly CompositeFormat VaapiCacheKeyFormat =
CompositeFormat.Parse("ffmpeg.hardware.vaapi.{0}.{1}.{2}"); CompositeFormat.Parse("ffmpeg.hardware.vaapi.{0}.{1}.{2}");
private static readonly CompositeFormat VaapiGenerationCacheKeyFormat =
CompositeFormat.Parse("ffmpeg.hardware.vaapi.generation.{0}.{1}.{2}");
private static readonly CompositeFormat QsvCacheKeyFormat = CompositeFormat.Parse("ffmpeg.hardware.qsv.{0}"); private static readonly CompositeFormat QsvCacheKeyFormat = CompositeFormat.Parse("ffmpeg.hardware.qsv.{0}");
private static readonly CompositeFormat FFmpegCapabilitiesCacheKeyFormat = CompositeFormat.Parse("ffmpeg.{0}"); private static readonly CompositeFormat FFmpegCapabilitiesCacheKeyFormat = CompositeFormat.Parse("ffmpeg.{0}");
@ -467,12 +470,25 @@ public partial class HardwareCapabilitiesFactory(
string display = vaapiDisplay.IfNone("drm"); string display = vaapiDisplay.IfNone("drm");
string driver = vaapiDriver.IfNone(string.Empty); string driver = vaapiDriver.IfNone(string.Empty);
string device = vaapiDevice.IfNone(string.Empty); string device = vaapiDevice.IfNone(string.Empty);
string generation = string.Empty;
var cacheKey = string.Format(CultureInfo.InvariantCulture, VaapiCacheKeyFormat, display, driver, device); var cacheKey = string.Format(CultureInfo.InvariantCulture, VaapiCacheKeyFormat, display, driver, device);
var generationCacheKey = string.Format(
CultureInfo.InvariantCulture,
VaapiGenerationCacheKeyFormat,
display,
driver,
device);
if (memoryCache.TryGetValue(cacheKey, out List<VaapiProfileEntrypoint>? profileEntrypoints) && if (memoryCache.TryGetValue(cacheKey, out List<VaapiProfileEntrypoint>? profileEntrypoints) &&
profileEntrypoints is not null) profileEntrypoints is not null)
{ {
return new VaapiHardwareCapabilities(profileEntrypoints, logger); if (memoryCache.TryGetValue(generationCacheKey, out string? cachedGeneration) &&
cachedGeneration is not null)
{
generation = cachedGeneration;
}
return new VaapiHardwareCapabilities(profileEntrypoints, generation, logger);
} }
Option<string> output = await GetVaapiOutput(display, vaapiDriver, device); Option<string> output = await GetVaapiOutput(display, vaapiDriver, device);
@ -485,6 +501,7 @@ public partial class HardwareCapabilitiesFactory(
foreach (string o in output) foreach (string o in output)
{ {
profileEntrypoints = VaapiCapabilityParser.ParseFull(o); profileEntrypoints = VaapiCapabilityParser.ParseFull(o);
generation = VaapiCapabilityParser.ParseGeneration(o);
} }
if (profileEntrypoints is not null && profileEntrypoints.Count != 0) if (profileEntrypoints is not null && profileEntrypoints.Count != 0)
@ -507,7 +524,8 @@ public partial class HardwareCapabilitiesFactory(
} }
memoryCache.Set(cacheKey, profileEntrypoints); memoryCache.Set(cacheKey, profileEntrypoints);
return new VaapiHardwareCapabilities(profileEntrypoints, logger); memoryCache.Set(generationCacheKey, generation);
return new VaapiHardwareCapabilities(profileEntrypoints, generation, logger);
} }
} }
catch (Exception ex) catch (Exception ex)
@ -541,7 +559,7 @@ public partial class HardwareCapabilitiesFactory(
if (memoryCache.TryGetValue(cacheKey, out List<VaapiProfileEntrypoint>? profileEntrypoints) && if (memoryCache.TryGetValue(cacheKey, out List<VaapiProfileEntrypoint>? profileEntrypoints) &&
profileEntrypoints is not null) profileEntrypoints is not null)
{ {
return new VaapiHardwareCapabilities(profileEntrypoints, logger); return new VaapiHardwareCapabilities(profileEntrypoints, string.Empty, logger);
} }
QsvOutput output = await GetQsvOutput(ffmpegPath, qsvDevice); QsvOutput output = await GetQsvOutput(ffmpegPath, qsvDevice);
@ -583,7 +601,7 @@ public partial class HardwareCapabilitiesFactory(
device); device);
memoryCache.Set(cacheKey, profileEntrypoints); memoryCache.Set(cacheKey, profileEntrypoints);
return new VaapiHardwareCapabilities(profileEntrypoints, logger); return new VaapiHardwareCapabilities(profileEntrypoints, string.Empty, logger);
} }
} }
} }

43
ErsatzTV.FFmpeg/Capabilities/Vaapi/VaapiCapabilityParser.cs

@ -2,7 +2,7 @@ using System.Text.RegularExpressions;
namespace ErsatzTV.FFmpeg.Capabilities.Vaapi; namespace ErsatzTV.FFmpeg.Capabilities.Vaapi;
public static class VaapiCapabilityParser public static partial class VaapiCapabilityParser
{ {
public static List<VaapiProfileEntrypoint> Parse(string output) public static List<VaapiProfileEntrypoint> Parse(string output)
{ {
@ -10,8 +10,7 @@ public static class VaapiCapabilityParser
foreach (string line in string.Join("", output).Split("\n")) foreach (string line in string.Join("", output).Split("\n"))
{ {
const string PROFILE_ENTRYPOINT_PATTERN = @"(VAProfile\w*).*(VAEntrypoint\w*)"; Match match = ProfileEntrypointRegex().Match(line);
Match match = Regex.Match(line, PROFILE_ENTRYPOINT_PATTERN);
if (match.Success) if (match.Success)
{ {
profileEntrypoints.Add( profileEntrypoints.Add(
@ -33,9 +32,7 @@ public static class VaapiCapabilityParser
for (var i = 0; i < allLines.Length; i++) for (var i = 0; i < allLines.Length; i++)
{ {
string line = allLines[i]; string line = allLines[i];
const string PROFILE_ENTRYPOINT_PATTERN = @"(VAProfile\w*).*(VAEntrypoint\w*)"; Match match = ProfileEntrypointRegex().Match(line);
const string PROFILE_RATE_CONTROL_PATTERN = @".*VA_RC_(\w*).*";
Match match = Regex.Match(line, PROFILE_ENTRYPOINT_PATTERN);
if (match.Success) if (match.Success)
{ {
profile = new VaapiProfileEntrypoint(match.Groups[1].Value.Trim(), match.Groups[2].Value.Trim()); profile = new VaapiProfileEntrypoint(match.Groups[1].Value.Trim(), match.Groups[2].Value.Trim());
@ -44,7 +41,7 @@ public static class VaapiCapabilityParser
else else
{ {
// check for rate control // check for rate control
match = Regex.Match(line, PROFILE_RATE_CONTROL_PATTERN); match = ProfileRateControlRegex().Match(line);
if (match.Success) if (match.Success)
{ {
switch (match.Groups[1].Value.Trim().ToLowerInvariant()) switch (match.Groups[1].Value.Trim().ToLowerInvariant())
@ -65,4 +62,36 @@ public static class VaapiCapabilityParser
return profileEntrypoints; return profileEntrypoints;
} }
public static string ParseGeneration(string output)
{
string generation = string.Empty;
Match match = MiscGenerationRegex().Match(output);
if (match.Success)
{
generation = match.Groups[1].Value.Trim().ToLowerInvariant();
if (generation is "radeonsi")
{
match = RadeonSiGenerationRegex().Match(output);
if (match.Success)
{
generation = match.Groups[1].Value.Trim().ToLowerInvariant();
}
}
}
return generation;
}
[GeneratedRegex(@"(VAProfile\w*).*(VAEntrypoint\w*)")]
private static partial Regex ProfileEntrypointRegex();
[GeneratedRegex(@".*VA_RC_(\w*).*")]
private static partial Regex ProfileRateControlRegex();
[GeneratedRegex(@"Driver version:.*\(radeonsi, (\w+)")]
private static partial Regex RadeonSiGenerationRegex();
[GeneratedRegex(@"Driver version:.*\((\w+),")]
private static partial Regex MiscGenerationRegex();
} }

76
ErsatzTV.FFmpeg/Capabilities/VaapiHardwareCapabilities.cs

@ -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

2
ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

@ -355,7 +355,7 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
if (currentState.FrameDataLocation == FrameDataLocation.Hardware) if (currentState.FrameDataLocation == FrameDataLocation.Hardware)
{ {
result.Add(new VaapiFormatFilter(format)); result.Add(new VaapiFormatFilter(format));
} }
else else
{ {

Loading…
Cancel
Save