add vaapi driver setting and health check (#377)
* add vaapi driver option * add vaapi driver setting and health check
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-1
@@ -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 =>
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>();
|
||||
|
||||
Reference in New Issue
Block a user