Browse Source

add ffmpeg profile pad mode (#2775)

* add ffmpeg profile pad mode

* update changelog
pull/2777/head
Jason Dove 7 months ago committed by GitHub
parent
commit
ccb917d0df
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      CHANGELOG.md
  2. 1
      ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfile.cs
  3. 10
      ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfileHandler.cs
  4. 1
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfile.cs
  5. 11
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs
  6. 1
      ErsatzTV.Application/FFmpegProfiles/FFmpegProfileViewModel.cs
  7. 1
      ErsatzTV.Application/FFmpegProfiles/Mapper.cs
  8. 3
      ErsatzTV.Core/Domain/FFmpegProfile.cs
  9. 7
      ErsatzTV.Core/Domain/FilterMode.cs
  10. 10
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  11. 4
      ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs
  12. 7
      ErsatzTV.FFmpeg/FFmpegFilterMode.cs
  13. 1
      ErsatzTV.FFmpeg/FrameState.cs
  14. 19
      ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs
  15. 7024
      ErsatzTV.Infrastructure.MySql/Migrations/20260115145631_Add_FFmpegProfilePadMode.Designer.cs
  16. 29
      ErsatzTV.Infrastructure.MySql/Migrations/20260115145631_Add_FFmpegProfilePadMode.cs
  17. 3
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  18. 6851
      ErsatzTV.Infrastructure.Sqlite/Migrations/20260115145551_Add_FFmpegProfilePadMode.Designer.cs
  19. 29
      ErsatzTV.Infrastructure.Sqlite/Migrations/20260115145551_Add_FFmpegProfilePadMode.cs
  20. 3
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  21. 12
      ErsatzTV/Pages/FFmpegEditor.razor
  22. 34
      ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

5
CHANGELOG.md

@ -10,6 +10,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- fr-FR can match sunday using `day_of_week = 6` - fr-FR can match sunday using `day_of_week = 6`
- As a complete example, to match Saturday from 9pm (inclusive) to 11pm (exclusive), based on content start time - As a complete example, to match Saturday from 9pm (inclusive) to 11pm (exclusive), based on content start time
- `content_condition: day_of_week = 6 and (time_of_day_seconds >= 75600 and time_of_day_seconds < 82800)` - `content_condition: day_of_week = 6 and (time_of_day_seconds >= 75600 and time_of_day_seconds < 82800)`
- Add `Pad Mode` to ffmpeg profile. Options are:
- `Hardware If Possible` - default/existing behavior when hardware acceleration is properly configured
- `Software` - force software padding
- This can be used to work around buggy GPU driver behavior where padding is green instead of black
- This is most often seen with VAAPI acceleration (radeonsi or i965 drivers)
### Fixed ### Fixed
- Use code signing on all Windows executables (`ErsatzTV-Windows.exe`, `ErsatzTV.exe`, `ErsatzTV.Scanner.exe`) - Use code signing on all Windows executables (`ErsatzTV-Windows.exe`, `ErsatzTV.exe`, `ErsatzTV.Scanner.exe`)

1
ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfile.cs

@ -14,6 +14,7 @@ public record CreateFFmpegProfile(
int? QsvExtraHardwareFrames, int? QsvExtraHardwareFrames,
int ResolutionId, int ResolutionId,
ScalingBehavior ScalingBehavior, ScalingBehavior ScalingBehavior,
FilterMode PadMode,
FFmpegProfileVideoFormat VideoFormat, FFmpegProfileVideoFormat VideoFormat,
string VideoProfile, string VideoProfile,
string VideoPreset, string VideoPreset,

10
ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfileHandler.cs

@ -1,6 +1,7 @@
using ErsatzTV.Core; using ErsatzTV.Core;
using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Interfaces.Search; using ErsatzTV.Core.Interfaces.Search;
using ErsatzTV.FFmpeg.Pipeline;
using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Infrastructure.Extensions; using ErsatzTV.Infrastructure.Extensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
@ -54,6 +55,15 @@ public class CreateFFmpegProfileHandler :
QsvExtraHardwareFrames = request.QsvExtraHardwareFrames, QsvExtraHardwareFrames = request.QsvExtraHardwareFrames,
ResolutionId = resolutionId, ResolutionId = resolutionId,
ScalingBehavior = request.ScalingBehavior, ScalingBehavior = request.ScalingBehavior,
// only allow customization with VAAPI accel
PadMode = request.HardwareAcceleration switch
{
HardwareAccelerationKind.None => FilterMode.Software,
HardwareAccelerationKind.Vaapi => request.PadMode,
_ => FilterMode.HardwareIfPossible
},
VideoFormat = request.VideoFormat, VideoFormat = request.VideoFormat,
VideoProfile = request.VideoProfile, VideoProfile = request.VideoProfile,
VideoPreset = request.VideoPreset, VideoPreset = request.VideoPreset,

1
ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfile.cs

@ -15,6 +15,7 @@ public record UpdateFFmpegProfile(
int? QsvExtraHardwareFrames, int? QsvExtraHardwareFrames,
int ResolutionId, int ResolutionId,
ScalingBehavior ScalingBehavior, ScalingBehavior ScalingBehavior,
FilterMode PadMode,
FFmpegProfileVideoFormat VideoFormat, FFmpegProfileVideoFormat VideoFormat,
string VideoProfile, string VideoProfile,
string VideoPreset, string VideoPreset,

11
ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs

@ -36,6 +36,7 @@ public class UpdateFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa
p.QsvExtraHardwareFrames = update.QsvExtraHardwareFrames; p.QsvExtraHardwareFrames = update.QsvExtraHardwareFrames;
p.ResolutionId = update.ResolutionId; p.ResolutionId = update.ResolutionId;
p.ScalingBehavior = update.ScalingBehavior; p.ScalingBehavior = update.ScalingBehavior;
p.PadMode = update.PadMode;
p.VideoFormat = update.VideoFormat; p.VideoFormat = update.VideoFormat;
p.VideoProfile = update.VideoProfile; p.VideoProfile = update.VideoProfile;
p.VideoPreset = update.VideoPreset; p.VideoPreset = update.VideoPreset;
@ -53,6 +54,16 @@ public class UpdateFFmpegProfileHandler(IDbContextFactory<TvContext> dbContextFa
p.VideoFormat = FFmpegProfileVideoFormat.Hevc; p.VideoFormat = FFmpegProfileVideoFormat.Hevc;
} }
// only allow customization with VAAPI accel
if (p.HardwareAcceleration is HardwareAccelerationKind.None)
{
p.PadMode = FilterMode.Software;
}
else if (p.HardwareAcceleration is not HardwareAccelerationKind.Vaapi)
{
p.PadMode = FilterMode.HardwareIfPossible;
}
p.VideoBitrate = update.VideoBitrate; p.VideoBitrate = update.VideoBitrate;
p.VideoBufferSize = update.VideoBufferSize; p.VideoBufferSize = update.VideoBufferSize;
p.TonemapAlgorithm = update.TonemapAlgorithm; p.TonemapAlgorithm = update.TonemapAlgorithm;

1
ErsatzTV.Application/FFmpegProfiles/FFmpegProfileViewModel.cs

@ -15,6 +15,7 @@ public record FFmpegProfileViewModel(
int? QsvExtraHardwareFrames, int? QsvExtraHardwareFrames,
ResolutionViewModel Resolution, ResolutionViewModel Resolution,
ScalingBehavior ScalingBehavior, ScalingBehavior ScalingBehavior,
FilterMode PadMode,
FFmpegProfileVideoFormat VideoFormat, FFmpegProfileVideoFormat VideoFormat,
string VideoProfile, string VideoProfile,
string VideoPreset, string VideoPreset,

1
ErsatzTV.Application/FFmpegProfiles/Mapper.cs

@ -17,6 +17,7 @@ internal static class Mapper
profile.QsvExtraHardwareFrames, profile.QsvExtraHardwareFrames,
Resolutions.Mapper.ProjectToViewModel(profile.Resolution), Resolutions.Mapper.ProjectToViewModel(profile.Resolution),
profile.ScalingBehavior, profile.ScalingBehavior,
profile.PadMode,
profile.VideoFormat, profile.VideoFormat,
profile.VideoProfile, profile.VideoProfile,
profile.VideoPreset ?? string.Empty, profile.VideoPreset ?? string.Empty,

3
ErsatzTV.Core/Domain/FFmpegProfile.cs

@ -15,6 +15,7 @@ public record FFmpegProfile
public int ResolutionId { get; set; } public int ResolutionId { get; set; }
public Resolution Resolution { get; set; } public Resolution Resolution { get; set; }
public ScalingBehavior ScalingBehavior { get; set; } public ScalingBehavior ScalingBehavior { get; set; }
public FilterMode PadMode { get; set; }
public FFmpegProfileVideoFormat VideoFormat { get; set; } public FFmpegProfileVideoFormat VideoFormat { get; set; }
public string VideoProfile { get; set; } public string VideoProfile { get; set; }
public string VideoPreset { get; set; } public string VideoPreset { get; set; }
@ -40,6 +41,8 @@ public record FFmpegProfile
ThreadCount = 0, ThreadCount = 0,
ResolutionId = resolution.Id, ResolutionId = resolution.Id,
Resolution = resolution, Resolution = resolution,
ScalingBehavior = ScalingBehavior.ScaleAndPad,
PadMode = FilterMode.Software,
VideoFormat = FFmpegProfileVideoFormat.H264, VideoFormat = FFmpegProfileVideoFormat.H264,
VideoProfile = "high", VideoProfile = "high",
VideoPreset = ErsatzTV.FFmpeg.Preset.VideoPreset.Unset, VideoPreset = ErsatzTV.FFmpeg.Preset.VideoPreset.Unset,

7
ErsatzTV.Core/Domain/FilterMode.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.Core.Domain;
public enum FilterMode
{
HardwareIfPossible = 0,
Software = 1
}

10
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -509,7 +509,10 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
scaledSize, scaledSize,
paddedSize, paddedSize,
cropSize, cropSize,
false, channel.FFmpegProfile.PadMode is FilterMode.HardwareIfPossible
? FFmpegFilterMode.HardwareIfPossible
: FFmpegFilterMode.Software,
IsAnamorphic: false,
playbackSettings.FrameRate, playbackSettings.FrameRate,
playbackSettings.VideoBitrate, playbackSettings.VideoBitrate,
playbackSettings.VideoBufferSize, playbackSettings.VideoBufferSize,
@ -711,7 +714,10 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
new FrameSize(desiredResolution.Width, desiredResolution.Height), new FrameSize(desiredResolution.Width, desiredResolution.Height),
new FrameSize(desiredResolution.Width, desiredResolution.Height), new FrameSize(desiredResolution.Width, desiredResolution.Height),
Option<FrameSize>.None, Option<FrameSize>.None,
false, channel.FFmpegProfile.PadMode is FilterMode.HardwareIfPossible
? FFmpegFilterMode.HardwareIfPossible
: FFmpegFilterMode.Software,
IsAnamorphic: false,
playbackSettings.FrameRate, playbackSettings.FrameRate,
playbackSettings.VideoBitrate, playbackSettings.VideoBitrate,
playbackSettings.VideoBufferSize, playbackSettings.VideoBufferSize,

4
ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs

@ -67,6 +67,7 @@ public class PipelineBuilderBaseTests
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
Option<FrameSize>.None, Option<FrameSize>.None,
FFmpegFilterMode.HardwareIfPossible,
false, false,
Option<FrameRate>.None, Option<FrameRate>.None,
2000, 2000,
@ -168,6 +169,7 @@ public class PipelineBuilderBaseTests
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
Option<FrameSize>.None, Option<FrameSize>.None,
FFmpegFilterMode.HardwareIfPossible,
false, false,
Option<FrameRate>.None, Option<FrameRate>.None,
2000, 2000,
@ -327,6 +329,7 @@ public class PipelineBuilderBaseTests
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
Option<FrameSize>.None, Option<FrameSize>.None,
FFmpegFilterMode.HardwareIfPossible,
false, false,
Option<FrameRate>.None, Option<FrameRate>.None,
2000, 2000,
@ -421,6 +424,7 @@ public class PipelineBuilderBaseTests
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
new FrameSize(1920, 1080), new FrameSize(1920, 1080),
Option<FrameSize>.None, Option<FrameSize>.None,
FFmpegFilterMode.HardwareIfPossible,
false, false,
Option<FrameRate>.None, Option<FrameRate>.None,
2000, 2000,

7
ErsatzTV.FFmpeg/FFmpegFilterMode.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.FFmpeg;
public enum FFmpegFilterMode
{
HardwareIfPossible = 0,
Software = 1
}

1
ErsatzTV.FFmpeg/FrameState.cs

@ -13,6 +13,7 @@ public record FrameState(
FrameSize ScaledSize, FrameSize ScaledSize,
FrameSize PaddedSize, FrameSize PaddedSize,
Option<FrameSize> CroppedSize, Option<FrameSize> CroppedSize,
FFmpegFilterMode PadMode,
bool IsAnamorphic, bool IsAnamorphic,
Option<FrameRate> FrameRate, Option<FrameRate> FrameRate,
Option<int> VideoBitrate, Option<int> VideoBitrate,

19
ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

@ -199,7 +199,7 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
bool isHdrTonemap = videoStream.ColorParams.IsHdr; bool isHdrTonemap = videoStream.ColorParams.IsHdr;
currentState = SetTonemap(videoInputFile, videoStream, ffmpegState, desiredState, currentState); currentState = SetTonemap(videoInputFile, videoStream, ffmpegState, desiredState, currentState);
currentState = SetPad(videoInputFile, ffmpegState, desiredState, currentState, isHdrTonemap); currentState = SetPad(videoInputFile, desiredState, currentState, isHdrTonemap);
// _logger.LogDebug("After pad: {PixelFormat}", currentState.PixelFormat); // _logger.LogDebug("After pad: {PixelFormat}", currentState.PixelFormat);
currentState = SetCrop(videoInputFile, desiredState, currentState); currentState = SetCrop(videoInputFile, desiredState, currentState);
@ -617,28 +617,13 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
private static FrameState SetPad( private static FrameState SetPad(
VideoInputFile videoInputFile, VideoInputFile videoInputFile,
FFmpegState ffmpegState,
FrameState desiredState, FrameState desiredState,
FrameState currentState, FrameState currentState,
bool isHdrTonemap) bool isHdrTonemap)
{ {
if (desiredState.CroppedSize.IsNone && currentState.PaddedSize != desiredState.PaddedSize) if (desiredState.CroppedSize.IsNone && currentState.PaddedSize != desiredState.PaddedSize)
{ {
// pad_vaapi seems to pad with green when input is HDR if (desiredState.PadMode is FFmpegFilterMode.Software || isHdrTonemap)
// also green with i965 driver
// also green with radeonsi and h264 main profile
// so use software pad in these cases
bool is965 = ffmpegState.VaapiDriver
.IfNone(string.Empty)
.Contains("i965", StringComparison.OrdinalIgnoreCase);
bool isRadeonSiMain = ffmpegState.VaapiDriver.IfNone(string.Empty)
.Contains("radeonsi", StringComparison.OrdinalIgnoreCase)
&& ffmpegState.EncoderHardwareAccelerationMode is HardwareAccelerationMode.Vaapi
&& desiredState.VideoFormat is VideoFormat.H264
&& desiredState.VideoProfile.IfNone(string.Empty) is VideoProfile.Main;
if (isHdrTonemap || is965 || isRadeonSiMain)
{ {
var padStep = new PadFilter(currentState, desiredState.PaddedSize); var padStep = new PadFilter(currentState, desiredState.PaddedSize);
currentState = padStep.NextState(currentState); currentState = padStep.NextState(currentState);

7024
ErsatzTV.Infrastructure.MySql/Migrations/20260115145631_Add_FFmpegProfilePadMode.Designer.cs generated

File diff suppressed because it is too large Load Diff

29
ErsatzTV.Infrastructure.MySql/Migrations/20260115145631_Add_FFmpegProfilePadMode.cs

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.MySql.Migrations
{
/// <inheritdoc />
public partial class Add_FFmpegProfilePadMode : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "PadMode",
table: "FFmpegProfile",
type: "int",
nullable: false,
defaultValue: 0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PadMode",
table: "FFmpegProfile");
}
}
}

3
ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs

@ -765,6 +765,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.Property<int>("NormalizeLoudnessMode") b.Property<int>("NormalizeLoudnessMode")
.HasColumnType("int"); .HasColumnType("int");
b.Property<int>("PadMode")
.HasColumnType("int");
b.Property<int?>("QsvExtraHardwareFrames") b.Property<int?>("QsvExtraHardwareFrames")
.HasColumnType("int"); .HasColumnType("int");

6851
ErsatzTV.Infrastructure.Sqlite/Migrations/20260115145551_Add_FFmpegProfilePadMode.Designer.cs generated

File diff suppressed because it is too large Load Diff

29
ErsatzTV.Infrastructure.Sqlite/Migrations/20260115145551_Add_FFmpegProfilePadMode.cs

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
{
/// <inheritdoc />
public partial class Add_FFmpegProfilePadMode : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "PadMode",
table: "FFmpegProfile",
type: "INTEGER",
nullable: false,
defaultValue: 0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PadMode",
table: "FFmpegProfile");
}
}
}

3
ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs

@ -734,6 +734,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.Property<int>("NormalizeLoudnessMode") b.Property<int>("NormalizeLoudnessMode")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<int>("PadMode")
.HasColumnType("INTEGER");
b.Property<int?>("QsvExtraHardwareFrames") b.Property<int?>("QsvExtraHardwareFrames")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");

12
ErsatzTV/Pages/FFmpegEditor.razor

@ -57,6 +57,18 @@
<MudSelectItem Value="@ScalingBehavior.Crop">Crop</MudSelectItem> <MudSelectItem Value="@ScalingBehavior.Crop">Crop</MudSelectItem>
</MudSelect> </MudSelect>
</MudStack> </MudStack>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
<div class="d-flex">
<MudText>Pad Mode</MudText>
</div>
<MudSelect @bind-Value="_model.PadMode"
For="@(() => _model.PadMode)"
Disabled="_model.HardwareAcceleration is not HardwareAccelerationKind.Vaapi"
HelperText="If hardware padding is green, software padding should be used instead">
<MudSelectItem Value="@FilterMode.HardwareIfPossible">Hardware If Possible</MudSelectItem>
<MudSelectItem Value="@FilterMode.Software">Software</MudSelectItem>
</MudSelect>
</MudStack>
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Video</MudText> <MudText Typo="Typo.h5" Class="mt-10 mb-2">Video</MudText>
<MudDivider Class="mb-6"/> <MudDivider Class="mb-6"/>
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5"> <MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">

34
ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

@ -7,9 +7,6 @@ namespace ErsatzTV.ViewModels;
public class FFmpegProfileEditViewModel public class FFmpegProfileEditViewModel
{ {
private string _videoProfile;
private NormalizeLoudnessMode _normalizeLoudnessMode;
public FFmpegProfileEditViewModel() public FFmpegProfileEditViewModel()
{ {
} }
@ -29,6 +26,7 @@ public class FFmpegProfileEditViewModel
DeinterlaceVideo = viewModel.DeinterlaceVideo; DeinterlaceVideo = viewModel.DeinterlaceVideo;
Resolution = viewModel.Resolution; Resolution = viewModel.Resolution;
ScalingBehavior = viewModel.ScalingBehavior; ScalingBehavior = viewModel.ScalingBehavior;
PadMode = viewModel.PadMode;
ThreadCount = viewModel.ThreadCount; ThreadCount = viewModel.ThreadCount;
HardwareAcceleration = viewModel.HardwareAcceleration; HardwareAcceleration = viewModel.HardwareAcceleration;
VaapiDisplay = viewModel.VaapiDisplay; VaapiDisplay = viewModel.VaapiDisplay;
@ -53,13 +51,14 @@ public class FFmpegProfileEditViewModel
public NormalizeLoudnessMode NormalizeLoudnessMode public NormalizeLoudnessMode NormalizeLoudnessMode
{ {
get => _normalizeLoudnessMode; get;
set set
{ {
if (_normalizeLoudnessMode != value) if (field != value)
{ {
_normalizeLoudnessMode = value; field = value;
if (_normalizeLoudnessMode is NormalizeLoudnessMode.LoudNorm) if (field is NormalizeLoudnessMode.LoudNorm)
{ {
TargetLoudness = -16; TargetLoudness = -16;
} }
@ -78,6 +77,20 @@ public class FFmpegProfileEditViewModel
public bool DeinterlaceVideo { get; set; } public bool DeinterlaceVideo { get; set; }
public ResolutionViewModel Resolution { get; set; } public ResolutionViewModel Resolution { get; set; }
public ScalingBehavior ScalingBehavior { get; set; } public ScalingBehavior ScalingBehavior { get; set; }
public FilterMode PadMode
{
// only allow customization with VAAPI accel
get => HardwareAcceleration switch
{
HardwareAccelerationKind.None => FilterMode.Software,
HardwareAccelerationKind.Vaapi => field,
_ => FilterMode.HardwareIfPossible
};
set;
}
public int ThreadCount { get; set; } public int ThreadCount { get; set; }
public HardwareAccelerationKind HardwareAcceleration { get; set; } public HardwareAccelerationKind HardwareAcceleration { get; set; }
public string VaapiDisplay { get; set; } public string VaapiDisplay { get; set; }
@ -95,10 +108,11 @@ public class FFmpegProfileEditViewModel
{ {
(HardwareAccelerationKind.Nvenc, FFmpegProfileVideoFormat.H264, FFmpegProfileBitDepth.TenBit) => FFmpeg (HardwareAccelerationKind.Nvenc, FFmpegProfileVideoFormat.H264, FFmpegProfileBitDepth.TenBit) => FFmpeg
.Format.VideoProfile.High444p, .Format.VideoProfile.High444p,
(_, FFmpegProfileVideoFormat.H264, _) => _videoProfile, (_, FFmpegProfileVideoFormat.H264, _) => field,
_ => string.Empty _ => string.Empty
}; };
set => _videoProfile = value;
set;
} }
public string VideoPreset { get; set; } public string VideoPreset { get; set; }
@ -117,6 +131,7 @@ public class FFmpegProfileEditViewModel
QsvExtraHardwareFrames, QsvExtraHardwareFrames,
Resolution.Id, Resolution.Id,
ScalingBehavior, ScalingBehavior,
PadMode,
VideoFormat, VideoFormat,
VideoProfile, VideoProfile,
VideoPreset, VideoPreset,
@ -148,6 +163,7 @@ public class FFmpegProfileEditViewModel
QsvExtraHardwareFrames, QsvExtraHardwareFrames,
Resolution.Id, Resolution.Id,
ScalingBehavior, ScalingBehavior,
PadMode,
VideoFormat, VideoFormat,
VideoProfile, VideoProfile,
VideoPreset, VideoPreset,

Loading…
Cancel
Save