Browse Source

add vaapi driver setting and health check (#377)

* add vaapi driver option

* add vaapi driver setting and health check
pull/378/head
Jason Dove 4 years ago committed by GitHub
parent
commit
f1f50e883c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs
  2. 5
      ErsatzTV.Application/FFmpegProfiles/FFmpegSettingsViewModel.cs
  3. 4
      ErsatzTV.Application/FFmpegProfiles/Queries/GetFFmpegSettingsHandler.cs
  4. 10
      ErsatzTV.Application/Health/Queries/GetAllHealthCheckResultsHandler.cs
  5. 7
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  6. 1
      ErsatzTV.Core/Domain/ConfigElementKey.cs
  7. 27
      ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
  8. 4
      ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
  9. 12
      ErsatzTV.Core/FFmpeg/VaapiDriver.cs
  10. 6
      ErsatzTV.Core/Health/Checks/IVaapiDriverHealthCheck.cs
  11. 9
      ErsatzTV.Core/Health/HealthCheckStatus.cs
  12. 3
      ErsatzTV.Infrastructure/Health/Checks/BaseHealthCheck.cs
  13. 45
      ErsatzTV.Infrastructure/Health/Checks/VaapiDriverHealthCheck.cs
  14. 6
      ErsatzTV.Infrastructure/Health/HealthCheckService.cs
  15. 7
      ErsatzTV/Pages/Settings.razor
  16. 1
      ErsatzTV/Startup.cs

4
ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegSettingsHandler.cs

@ -115,6 +115,10 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands @@ -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;
}
}

5
ErsatzTV.Application/FFmpegProfiles/FFmpegSettingsViewModel.cs

@ -1,4 +1,6 @@ @@ -1,4 +1,6 @@
namespace ErsatzTV.Application.FFmpegProfiles
using ErsatzTV.Core.FFmpeg;
namespace ErsatzTV.Application.FFmpegProfiles
{
public class FFmpegSettingsViewModel
{
@ -8,5 +10,6 @@ @@ -8,5 +10,6 @@
public string PreferredLanguageCode { get; set; }
public bool SaveReports { get; set; }
public int? GlobalWatermarkId { get; set; }
public VaapiDriver VaapiDriver { get; set; }
}
}

4
ErsatzTV.Application/FFmpegProfiles/Queries/GetFFmpegSettingsHandler.cs

@ -1,6 +1,7 @@ @@ -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 @@ -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 @@ -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)

10
ErsatzTV.Application/Health/Queries/GetAllHealthCheckResultsHandler.cs

@ -1,4 +1,5 @@ @@ -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 @@ -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();
}
}
}

7
ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs

@ -99,6 +99,10 @@ namespace ErsatzTV.Application.Streaming.Queries @@ -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 @@ -108,7 +112,8 @@ namespace ErsatzTV.Application.Streaming.Queries
playoutItemWithPath.Path,
playoutItemWithPath.PlayoutItem.StartOffset,
now,
maybeGlobalWatermark));
maybeGlobalWatermark,
maybeVaapiDriver));
},
async error =>
{

1
ErsatzTV.Core/Domain/ConfigElementKey.cs

@ -13,6 +13,7 @@ @@ -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");

27
ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs

@ -43,6 +43,8 @@ namespace ErsatzTV.Core.FFmpeg @@ -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 @@ -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 @@ -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 @@ -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

4
ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs

@ -34,7 +34,8 @@ namespace ErsatzTV.Core.FFmpeg @@ -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 @@ -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
ErsatzTV.Core/FFmpeg/VaapiDriver.cs

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
using System.Diagnostics.CodeAnalysis;
namespace ErsatzTV.Core.FFmpeg
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
public enum VaapiDriver
{
Default = 0,
iHD = 1,
i965 = 2
}
}

6
ErsatzTV.Core/Health/Checks/IVaapiDriverHealthCheck.cs

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
namespace ErsatzTV.Core.Health.Checks
{
public interface IVaapiDriverHealthCheck : IHealthCheck
{
}
}

9
ErsatzTV.Core/Health/HealthCheckStatus.cs

@ -2,9 +2,10 @@ @@ -2,9 +2,10 @@
{
public enum HealthCheckStatus
{
Pass,
Fail,
Warning,
Info
Pass = 0,
Fail = 1,
Warning = 2,
Info = 3,
NotApplicable = 4
}
}

3
ErsatzTV.Infrastructure/Health/Checks/BaseHealthCheck.cs

@ -14,6 +14,9 @@ namespace ErsatzTV.Infrastructure.Health.Checks @@ -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);

45
ErsatzTV.Infrastructure/Health/Checks/VaapiDriverHealthCheck.cs

@ -0,0 +1,45 @@ @@ -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();
}
}
}

6
ErsatzTV.Infrastructure/Health/HealthCheckService.cs

@ -18,7 +18,8 @@ namespace ErsatzTV.Infrastructure.Health @@ -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 @@ -27,7 +28,8 @@ namespace ErsatzTV.Infrastructure.Health
hardwareAccelerationHealthCheck,
movieMetadataHealthCheck,
episodeMetadataHealthCheck,
zeroDurationHealthCheck
zeroDurationHealthCheck,
vaapiDriverHealthCheck
};
}

7
ErsatzTV/Pages/Settings.razor

@ -11,6 +11,7 @@ @@ -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 @@ @@ -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
ErsatzTV/Startup.cs

@ -208,6 +208,7 @@ namespace ErsatzTV @@ -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>();

Loading…
Cancel
Save