add vaapi driver setting and health check (#377)

* add vaapi driver option

* add vaapi driver setting and health check
This commit is contained in:
Jason Dove
2021-09-18 13:00:36 -05:00
committed by GitHub
parent 7506f49f5b
commit f1f50e883c
16 changed files with 139 additions and 12 deletions
@@ -115,6 +115,10 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
await _configElementRepository.Delete(ConfigElementKey.FFmpegGlobalWatermarkId);
}
await _configElementRepository.Upsert(
ConfigElementKey.FFmpegVaapiDriver,
(int)request.Settings.VaapiDriver);
return Unit.Default;
}
}
@@ -1,4 +1,6 @@
namespace ErsatzTV.Application.FFmpegProfiles
using ErsatzTV.Core.FFmpeg;
namespace ErsatzTV.Application.FFmpegProfiles
{
public class FFmpegSettingsViewModel
{
@@ -8,5 +10,6 @@
public string PreferredLanguageCode { get; set; }
public bool SaveReports { get; set; }
public int? GlobalWatermarkId { get; set; }
public VaapiDriver VaapiDriver { get; set; }
}
}
@@ -1,6 +1,7 @@
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
using MediatR;
@@ -28,6 +29,8 @@ namespace ErsatzTV.Application.FFmpegProfiles.Queries
await _configElementRepository.GetValue<string>(ConfigElementKey.FFmpegPreferredLanguageCode);
Option<int> watermark =
await _configElementRepository.GetValue<int>(ConfigElementKey.FFmpegGlobalWatermarkId);
Option<int> vaapiDriver =
await _configElementRepository.GetValue<int>(ConfigElementKey.FFmpegVaapiDriver);
var result = new FFmpegSettingsViewModel
{
@@ -36,6 +39,7 @@ namespace ErsatzTV.Application.FFmpegProfiles.Queries
DefaultFFmpegProfileId = await defaultFFmpegProfileId.IfNoneAsync(0),
SaveReports = await saveReports.IfNoneAsync(false),
PreferredLanguageCode = await preferredLanguageCode.IfNoneAsync("eng"),
VaapiDriver = (VaapiDriver)await vaapiDriver.IfNoneAsync(0)
};
foreach (int watermarkId in watermark)
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ErsatzTV.Core.Health;
@@ -13,9 +14,12 @@ namespace ErsatzTV.Application.Health.Queries
public GetAllHealthCheckResultsHandler(IHealthCheckService healthCheckService) =>
_healthCheckService = healthCheckService;
public Task<List<HealthCheckResult>> Handle(
public async Task<List<HealthCheckResult>> Handle(
GetAllHealthCheckResults request,
CancellationToken cancellationToken) =>
_healthCheckService.PerformHealthChecks();
CancellationToken cancellationToken)
{
List<HealthCheckResult> results = await _healthCheckService.PerformHealthChecks();
return results.Filter(r => r.Status != HealthCheckStatus.NotApplicable).ToList();
}
}
}
@@ -99,6 +99,10 @@ namespace ErsatzTV.Application.Streaming.Queries
watermarkId => dbContext.ChannelWatermarks
.SelectOneAsync(w => w.Id, w => w.Id == watermarkId));
Option<VaapiDriver> maybeVaapiDriver = await dbContext.ConfigElements
.GetValue<int>(ConfigElementKey.FFmpegVaapiDriver)
.MapT(i => (VaapiDriver)i);
return Right<BaseError, Process>(
await _ffmpegProcessService.ForPlayoutItem(
ffmpegPath,
@@ -108,7 +112,8 @@ namespace ErsatzTV.Application.Streaming.Queries
playoutItemWithPath.Path,
playoutItemWithPath.PlayoutItem.StartOffset,
now,
maybeGlobalWatermark));
maybeGlobalWatermark,
maybeVaapiDriver));
},
async error =>
{
+1
View File
@@ -13,6 +13,7 @@
public static ConfigElementKey FFmpegSaveReports => new("ffmpeg.save_reports");
public static ConfigElementKey FFmpegPreferredLanguageCode => new("ffmpeg.preferred_language_code");
public static ConfigElementKey FFmpegGlobalWatermarkId => new("ffmpeg.global_watermark_id");
public static ConfigElementKey FFmpegVaapiDriver => new("ffmpeg.vaapi_driver");
public static ConfigElementKey SearchIndexVersion => new("search_index.version");
public static ConfigElementKey HDHRTunerCount => new("hdhr.tuner_count");
public static ConfigElementKey ChannelsPageSize => new("pages.channels.page_size");
@@ -43,6 +43,8 @@ namespace ErsatzTV.Core.FFmpeg
private readonly bool _saveReports;
private FFmpegComplexFilterBuilder _complexFilterBuilder = new();
private bool _isConcat;
private VaapiDriver _vaapiDriver;
private HardwareAccelerationKind _hwAccel;
public FFmpegProcessBuilder(string ffmpegPath, bool saveReports)
{
@@ -50,6 +52,16 @@ namespace ErsatzTV.Core.FFmpeg
_saveReports = saveReports;
}
public FFmpegProcessBuilder WithVaapiDriver(Option<VaapiDriver> maybeVaapiDriver)
{
foreach (VaapiDriver vaapiDriver in maybeVaapiDriver)
{
_vaapiDriver = vaapiDriver;
}
return this;
}
public FFmpegProcessBuilder WithThreads(int threads)
{
_arguments.Add("-threads");
@@ -59,6 +71,8 @@ namespace ErsatzTV.Core.FFmpeg
public FFmpegProcessBuilder WithHardwareAcceleration(HardwareAccelerationKind hwAccel)
{
_hwAccel = hwAccel;
switch (hwAccel)
{
case HardwareAccelerationKind.Qsv:
@@ -433,6 +447,19 @@ namespace ErsatzTV.Core.FFmpeg
StandardOutputEncoding = Encoding.UTF8
};
if (_hwAccel == HardwareAccelerationKind.Vaapi)
{
switch (_vaapiDriver)
{
case VaapiDriver.i965:
startInfo.EnvironmentVariables.Add("LIBVA_DRIVER_NAME", "i965");
break;
case VaapiDriver.iHD:
startInfo.EnvironmentVariables.Add("LIBVA_DRIVER_NAME", "iHD");
break;
}
}
if (_saveReports)
{
string fileName = _isConcat
+3 -1
View File
@@ -34,7 +34,8 @@ namespace ErsatzTV.Core.FFmpeg
string path,
DateTimeOffset start,
DateTimeOffset now,
Option<ChannelWatermark> globalWatermark)
Option<ChannelWatermark> globalWatermark,
Option<VaapiDriver> maybeVaapiDriver)
{
MediaStream videoStream = await _ffmpegStreamSelector.SelectVideoStream(channel, version);
Option<MediaStream> maybeAudioStream = await _ffmpegStreamSelector.SelectAudioStream(channel, version);
@@ -58,6 +59,7 @@ namespace ErsatzTV.Core.FFmpeg
FFmpegProcessBuilder builder = new FFmpegProcessBuilder(ffmpegPath, saveReports)
.WithThreads(playbackSettings.ThreadCount)
.WithHardwareAcceleration(playbackSettings.HardwareAcceleration)
.WithVaapiDriver(maybeVaapiDriver)
.WithQuiet()
.WithFormatFlags(playbackSettings.FormatFlags)
.WithRealtimeOutput(playbackSettings.RealtimeOutput)
+12
View File
@@ -0,0 +1,12 @@
using System.Diagnostics.CodeAnalysis;
namespace ErsatzTV.Core.FFmpeg
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum VaapiDriver
{
Default = 0,
iHD = 1,
i965 = 2
}
}
@@ -0,0 +1,6 @@
namespace ErsatzTV.Core.Health.Checks
{
public interface IVaapiDriverHealthCheck : IHealthCheck
{
}
}
+5 -4
View File
@@ -2,9 +2,10 @@
{
public enum HealthCheckStatus
{
Pass,
Fail,
Warning,
Info
Pass = 0,
Fail = 1,
Warning = 2,
Info = 3,
NotApplicable = 4
}
}
@@ -14,6 +14,9 @@ namespace ErsatzTV.Infrastructure.Health.Checks
protected HealthCheckResult Result(HealthCheckStatus status, string message) =>
new(Title, status, message);
protected HealthCheckResult NotApplicableResult() =>
new(Title, HealthCheckStatus.NotApplicable, string.Empty);
protected HealthCheckResult OkResult() =>
new(Title, HealthCheckStatus.Pass, string.Empty);
@@ -0,0 +1,45 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.FFmpeg;
using ErsatzTV.Core.Health;
using ErsatzTV.Core.Health.Checks;
using ErsatzTV.Core.Interfaces.Repositories;
using LanguageExt;
namespace ErsatzTV.Infrastructure.Health.Checks
{
public class VaapiDriverHealthCheck : BaseHealthCheck, IVaapiDriverHealthCheck
{
private readonly IConfigElementRepository _configElementRepository;
public VaapiDriverHealthCheck(IConfigElementRepository configElementRepository) =>
_configElementRepository = configElementRepository;
protected override string Title => "VAAPI Driver";
public async Task<HealthCheckResult> Check()
{
string version = Assembly.GetEntryAssembly()?.GetCustomAttribute<AssemblyInformationalVersionAttribute>()
?.InformationalVersion ?? "unknown";
if (!version.Contains("docker", StringComparison.OrdinalIgnoreCase) ||
!version.Contains("vaapi", StringComparison.OrdinalIgnoreCase))
{
return NotApplicableResult();
}
Option<int> maybeVaapiDriver =
await _configElementRepository.GetValue<int>(ConfigElementKey.FFmpegVaapiDriver);
var vaapiDriver = (VaapiDriver)await maybeVaapiDriver.IfNoneAsync(0);
if (vaapiDriver == VaapiDriver.Default)
{
return InfoResult(
"Settings > FFmpeg Settings > VAAPI Driver is set to Default; selecting iHD (Gen 8+) or i965 (up to Gen 9) may offer better performance");
}
return OkResult();
}
}
}
@@ -18,7 +18,8 @@ namespace ErsatzTV.Infrastructure.Health
IHardwareAccelerationHealthCheck hardwareAccelerationHealthCheck,
IMovieMetadataHealthCheck movieMetadataHealthCheck,
IEpisodeMetadataHealthCheck episodeMetadataHealthCheck,
IZeroDurationHealthCheck zeroDurationHealthCheck)
IZeroDurationHealthCheck zeroDurationHealthCheck,
IVaapiDriverHealthCheck vaapiDriverHealthCheck)
{
_checks = new List<IHealthCheck>
{
@@ -27,7 +28,8 @@ namespace ErsatzTV.Infrastructure.Health
hardwareAccelerationHealthCheck,
movieMetadataHealthCheck,
episodeMetadataHealthCheck,
zeroDurationHealthCheck
zeroDurationHealthCheck,
vaapiDriverHealthCheck
};
}
+7
View File
@@ -11,6 +11,7 @@
@using ErsatzTV.Application.Configuration.Commands
@using ErsatzTV.Application.Watermarks
@using ErsatzTV.Application.Watermarks.Queries
@using ErsatzTV.Core.FFmpeg
@using Microsoft.AspNetCore.Components
@inject IMediator _mediator
@inject ISnackbar _snackbar
@@ -57,6 +58,12 @@
<MudSelectItem T="int?" Value="@watermark.Id">@watermark.Name</MudSelectItem>
}
</MudSelect>
<MudSelect Class="mt-3" Label="VAAPI Driver" @bind-Value="_ffmpegSettings.VaapiDriver" For="@(() => _ffmpegSettings.VaapiDriver)">
@foreach (VaapiDriver driver in Enum.GetValues<VaapiDriver>())
{
<MudSelectItem Value="@driver">@driver</MudSelectItem>
}
</MudSelect>
</MudForm>
</MudCardContent>
<MudCardActions>
+1
View File
@@ -208,6 +208,7 @@ namespace ErsatzTV
services.AddScoped<IMovieMetadataHealthCheck, MovieMetadataHealthCheck>();
services.AddScoped<IEpisodeMetadataHealthCheck, EpisodeMetadataHealthCheck>();
services.AddScoped<IZeroDurationHealthCheck, ZeroDurationHealthCheck>();
services.AddScoped<IVaapiDriverHealthCheck, VaapiDriverHealthCheck>();
services.AddScoped<IHealthCheckService, HealthCheckService>();
services.AddScoped<IChannelRepository, ChannelRepository>();