Browse Source

add tonemap algorithm setting to ffmpeg profile (#2039)

pull/2042/head
Jason Dove 1 week ago committed by GitHub
parent
commit
ea46a7a5ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 3
      CHANGELOG.md
  2. 1
      ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfile.cs
  3. 1
      ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfileHandler.cs
  4. 1
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfile.cs
  5. 1
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs
  6. 1
      ErsatzTV.Application/FFmpegProfiles/FFmpegProfileViewModel.cs
  7. 2
      ErsatzTV.Application/FFmpegProfiles/Mapper.cs
  8. 1
      ErsatzTV.Core/Api/FFmpegProfiles/FFmpegFullProfileResponseModel.cs
  9. 2
      ErsatzTV.Core/Domain/FFmpegProfile.cs
  10. 11
      ErsatzTV.Core/Domain/FFmpegProfileTonemapAlgorithm.cs
  11. 21
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  12. 1
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettings.cs
  13. 2
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs
  14. 12
      ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs
  15. 6
      ErsatzTV.FFmpeg/FFmpegState.cs
  16. 4
      ErsatzTV.FFmpeg/Filter/Cuda/TonemapCudaFilter.cs
  17. 6
      ErsatzTV.FFmpeg/Filter/TonemapFilter.cs
  18. 4
      ErsatzTV.FFmpeg/Filter/Vaapi/TonemapVaapiFilter.cs
  19. 4
      ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs
  20. 2
      ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs
  21. 5
      ErsatzTV.FFmpeg/Pipeline/SoftwarePipelineBuilder.cs
  22. 4
      ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs
  23. 11
      ErsatzTV.FFmpeg/TonemapAlgorithm.cs
  24. 5884
      ErsatzTV.Infrastructure.MySql/Migrations/20250615001516_Add_FFmpegProfile_TonemapAlgorithm.Designer.cs
  25. 29
      ErsatzTV.Infrastructure.MySql/Migrations/20250615001516_Add_FFmpegProfile_TonemapAlgorithm.cs
  26. 3
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  27. 5723
      ErsatzTV.Infrastructure.Sqlite/Migrations/20250615001824_Add_FFmpegProfile_TonemapAlgorithm.Designer.cs
  28. 29
      ErsatzTV.Infrastructure.Sqlite/Migrations/20250615001824_Add_FFmpegProfile_TonemapAlgorithm.cs
  29. 3
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  30. 13
      ErsatzTV/Pages/FFmpegEditor.razor
  31. 4
      ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

3
CHANGELOG.md

@ -26,7 +26,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -26,7 +26,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- VAAPI may use hardware-accelerated tone mapping (when opencl accel is also available)
- NVIDIA may use hardware-accelerated tone mapping (when vulkan accel and libplacebo filter are also available)
- QSV may use hardware-accelerated tone mapping (when hardware decoding is used)
- In all other cases, HDR content will use a software pipeline and the linear algorithm
- In all other cases, HDR content will use a software pipeline
- The tonemap algorithm can be configured in the ffmpeg profile
- Use hardware-accelerated padding with VAAPI
- Add environment variable `ETV_DISABLE_VULKAN`
- Any non-empty value will disable use of Vulkan acceleration and force software tonemapping

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

@ -21,6 +21,7 @@ public record CreateFFmpegProfile( @@ -21,6 +21,7 @@ public record CreateFFmpegProfile(
FFmpegProfileBitDepth BitDepth,
int VideoBitrate,
int VideoBufferSize,
FFmpegProfileTonemapAlgorithm TonemapAlgorithm,
FFmpegProfileAudioFormat AudioFormat,
int AudioBitrate,
int AudioBufferSize,

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

@ -60,6 +60,7 @@ public class CreateFFmpegProfileHandler : @@ -60,6 +60,7 @@ public class CreateFFmpegProfileHandler :
BitDepth = request.BitDepth,
VideoBitrate = request.VideoBitrate,
VideoBufferSize = request.VideoBufferSize,
TonemapAlgorithm = request.TonemapAlgorithm,
AudioFormat = request.AudioFormat,
AudioBitrate = request.AudioBitrate,
AudioBufferSize = request.AudioBufferSize,

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

@ -22,6 +22,7 @@ public record UpdateFFmpegProfile( @@ -22,6 +22,7 @@ public record UpdateFFmpegProfile(
FFmpegProfileBitDepth BitDepth,
int VideoBitrate,
int VideoBufferSize,
FFmpegProfileTonemapAlgorithm TonemapAlgorithm,
FFmpegProfileAudioFormat AudioFormat,
int AudioBitrate,
int AudioBufferSize,

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

@ -54,6 +54,7 @@ public class @@ -54,6 +54,7 @@ public class
p.VideoBitrate = update.VideoBitrate;
p.VideoBufferSize = update.VideoBufferSize;
p.TonemapAlgorithm = update.TonemapAlgorithm;
p.AudioFormat = update.AudioFormat;
p.AudioBitrate = update.AudioBitrate;
p.AudioBufferSize = update.AudioBufferSize;

1
ErsatzTV.Application/FFmpegProfiles/FFmpegProfileViewModel.cs

@ -22,6 +22,7 @@ public record FFmpegProfileViewModel( @@ -22,6 +22,7 @@ public record FFmpegProfileViewModel(
FFmpegProfileBitDepth BitDepth,
int VideoBitrate,
int VideoBufferSize,
FFmpegProfileTonemapAlgorithm TonemapAlgorithm,
FFmpegProfileAudioFormat AudioFormat,
int AudioBitrate,
int AudioBufferSize,

2
ErsatzTV.Application/FFmpegProfiles/Mapper.cs

@ -24,6 +24,7 @@ internal static class Mapper @@ -24,6 +24,7 @@ internal static class Mapper
profile.BitDepth,
profile.VideoBitrate,
profile.VideoBufferSize,
profile.TonemapAlgorithm,
profile.AudioFormat,
profile.AudioBitrate,
profile.AudioBufferSize,
@ -54,6 +55,7 @@ internal static class Mapper @@ -54,6 +55,7 @@ internal static class Mapper
(int)ffmpegProfile.VideoFormat,
ffmpegProfile.VideoBitrate,
ffmpegProfile.VideoBufferSize,
(int)ffmpegProfile.TonemapAlgorithm,
(int)ffmpegProfile.AudioFormat,
ffmpegProfile.AudioBitrate,
ffmpegProfile.AudioBufferSize,

1
ErsatzTV.Core/Api/FFmpegProfiles/FFmpegFullProfileResponseModel.cs

@ -12,6 +12,7 @@ public record FFmpegFullProfileResponseModel( @@ -12,6 +12,7 @@ public record FFmpegFullProfileResponseModel(
int VideoFormat,
int VideoBitrate,
int VideoBufferSize,
int TonemapAlgorithm,
int AudioFormat,
int AudioBitrate,
int AudioBufferSize,

2
ErsatzTV.Core/Domain/FFmpegProfile.cs

@ -22,6 +22,7 @@ public record FFmpegProfile @@ -22,6 +22,7 @@ public record FFmpegProfile
public FFmpegProfileBitDepth BitDepth { get; set; }
public int VideoBitrate { get; set; }
public int VideoBufferSize { get; set; }
public FFmpegProfileTonemapAlgorithm TonemapAlgorithm { get; set; }
public FFmpegProfileAudioFormat AudioFormat { get; set; }
public int AudioBitrate { get; set; }
public int AudioBufferSize { get; set; }
@ -45,6 +46,7 @@ public record FFmpegProfile @@ -45,6 +46,7 @@ public record FFmpegProfile
AudioFormat = FFmpegProfileAudioFormat.Aac,
VideoBitrate = 2000,
VideoBufferSize = 4000,
TonemapAlgorithm = FFmpegProfileTonemapAlgorithm.Linear,
AudioBitrate = 192,
AudioBufferSize = 384,
NormalizeLoudnessMode = NormalizeLoudnessMode.Off,

11
ErsatzTV.Core/Domain/FFmpegProfileTonemapAlgorithm.cs

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
namespace ErsatzTV.Core.Domain;
public enum FFmpegProfileTonemapAlgorithm
{
Linear = 0,
Clip = 1,
Gamma = 2,
Reinhard = 3,
Mobius = 4,
Hable = 5
}

21
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -399,7 +399,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -399,7 +399,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.ThreadCount,
qsvExtraHardwareFrames,
videoVersion is BackgroundImageMediaVersion { IsSongWithProgress: true },
IsHdrTonemap: false);
IsHdrTonemap: false,
GetTonemapAlgorithm(playbackSettings));
_logger.LogDebug("FFmpeg desired state {FrameState}", desiredState);
@ -554,7 +555,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -554,7 +555,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
Option<int>.None,
qsvExtraHardwareFrames,
IsSongWithProgress: false,
IsHdrTonemap: false);
IsHdrTonemap: false,
GetTonemapAlgorithm(playbackSettings));
var ffmpegSubtitleStream = new ErsatzTV.FFmpeg.MediaStream(0, "ass", StreamKind.Video);
@ -749,7 +751,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -749,7 +751,8 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.ThreadCount,
Optional(channel.FFmpegProfile.QsvExtraHardwareFrames),
IsSongWithProgress: false,
IsHdrTonemap: false);
IsHdrTonemap: false,
GetTonemapAlgorithm(playbackSettings));
_logger.LogDebug("FFmpeg desired state {FrameState}", desiredState);
@ -1039,6 +1042,18 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -1039,6 +1042,18 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
_ => throw new ArgumentOutOfRangeException($"unexpected video format {playbackSettings.VideoFormat}")
};
private static string GetTonemapAlgorithm(FFmpegPlaybackSettings playbackSettings) =>
playbackSettings.TonemapAlgorithm switch
{
FFmpegProfileTonemapAlgorithm.Linear => TonemapAlgorithm.Linear,
FFmpegProfileTonemapAlgorithm.Clip => TonemapAlgorithm.Clip,
FFmpegProfileTonemapAlgorithm.Gamma => TonemapAlgorithm.Gamma,
FFmpegProfileTonemapAlgorithm.Reinhard => TonemapAlgorithm.Reinhard,
FFmpegProfileTonemapAlgorithm.Mobius => TonemapAlgorithm.Mobius,
FFmpegProfileTonemapAlgorithm.Hable => TonemapAlgorithm.Hable,
_ => throw new ArgumentOutOfRangeException($"unexpected tonemap algorithm {playbackSettings.TonemapAlgorithm}")
};
private static Option<string> GetVideoProfile(string videoFormat, string videoProfile) =>
(videoFormat, (videoProfile ?? string.Empty).ToLowerInvariant()) switch
{

1
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettings.cs

@ -18,6 +18,7 @@ public class FFmpegPlaybackSettings @@ -18,6 +18,7 @@ public class FFmpegPlaybackSettings
public IPixelFormat PixelFormat { get; set; }
public Option<int> VideoBitrate { get; set; }
public Option<int> VideoBufferSize { get; set; }
public FFmpegProfileTonemapAlgorithm TonemapAlgorithm { get; set; }
public Option<int> AudioBitrate { get; set; }
public Option<int> AudioBufferSize { get; set; }
public Option<int> AudioChannels { get; set; }

2
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs

@ -116,6 +116,7 @@ public static class FFmpegPlaybackSettingsCalculator @@ -116,6 +116,7 @@ public static class FFmpegPlaybackSettingsCalculator
result.VideoFormat = ffmpegProfile.VideoFormat;
result.VideoBitrate = ffmpegProfile.VideoBitrate;
result.VideoBufferSize = ffmpegProfile.VideoBufferSize;
result.TonemapAlgorithm = ffmpegProfile.TonemapAlgorithm;
result.VideoDecoder =
(result.HardwareAcceleration, stream.Codec, stream.PixelFormat) switch
@ -184,6 +185,7 @@ public static class FFmpegPlaybackSettingsCalculator @@ -184,6 +185,7 @@ public static class FFmpegPlaybackSettingsCalculator
VideoFormat = ffmpegProfile.VideoFormat,
VideoBitrate = ffmpegProfile.VideoBitrate,
VideoBufferSize = ffmpegProfile.VideoBufferSize,
TonemapAlgorithm = ffmpegProfile.TonemapAlgorithm,
VideoDecoder = null,
PixelFormat = ffmpegProfile.BitDepth switch
{

12
ErsatzTV.FFmpeg.Tests/PipelineBuilderBaseTests.cs

@ -94,7 +94,8 @@ public class PipelineBuilderBaseTests @@ -94,7 +94,8 @@ public class PipelineBuilderBaseTests
Option<int>.None,
Option<int>.None,
false,
false);
false,
"clip");
var builder = new SoftwarePipelineBuilder(
new DefaultFFmpegCapabilities(),
@ -189,7 +190,8 @@ public class PipelineBuilderBaseTests @@ -189,7 +190,8 @@ public class PipelineBuilderBaseTests
Option<int>.None,
Option<int>.None,
false,
false);
false,
"clip");
var builder = new SoftwarePipelineBuilder(
new DefaultFFmpegCapabilities(),
@ -340,7 +342,8 @@ public class PipelineBuilderBaseTests @@ -340,7 +342,8 @@ public class PipelineBuilderBaseTests
Option<int>.None,
Option<int>.None,
false,
false);
false,
"clip");
var builder = new SoftwarePipelineBuilder(
new DefaultFFmpegCapabilities(),
@ -429,7 +432,8 @@ public class PipelineBuilderBaseTests @@ -429,7 +432,8 @@ public class PipelineBuilderBaseTests
Option<int>.None,
Option<int>.None,
false,
false);
false,
"clip");
var builder = new SoftwarePipelineBuilder(
new DefaultFFmpegCapabilities(),

6
ErsatzTV.FFmpeg/FFmpegState.cs

@ -23,7 +23,8 @@ public record FFmpegState( @@ -23,7 +23,8 @@ public record FFmpegState(
Option<int> ThreadCount,
Option<int> MaybeQsvExtraHardwareFrames,
bool IsSongWithProgress,
bool IsHdrTonemap)
bool IsHdrTonemap,
string TonemapAlgorithm)
{
public int QsvExtraHardwareFrames => MaybeQsvExtraHardwareFrames.IfNone(64);
@ -49,5 +50,6 @@ public record FFmpegState( @@ -49,5 +50,6 @@ public record FFmpegState(
Option<int>.None,
Option<int>.None,
false,
false);
false,
"linear");
}

4
ErsatzTV.FFmpeg/Filter/Cuda/TonemapCudaFilter.cs

@ -2,10 +2,10 @@ using ErsatzTV.FFmpeg.Format; @@ -2,10 +2,10 @@ using ErsatzTV.FFmpeg.Format;
namespace ErsatzTV.FFmpeg.Filter.Cuda;
public class TonemapCudaFilter(IPixelFormat desiredPixelFormat) : BaseFilter
public class TonemapCudaFilter(FFmpegState ffmpegState, IPixelFormat desiredPixelFormat) : BaseFilter
{
public override string Filter =>
$"libplacebo=tonemapping=auto:colorspace=bt709:color_primaries=bt709:color_trc=bt709:format={desiredPixelFormat.FFmpegName},hwupload_cuda";
$"libplacebo=tonemapping={ffmpegState.TonemapAlgorithm}:colorspace=bt709:color_primaries=bt709:color_trc=bt709:format={desiredPixelFormat.FFmpegName},hwupload_cuda";
public override FrameState NextState(FrameState currentState) =>
currentState with

6
ErsatzTV.FFmpeg/Filter/TonemapFilter.cs

@ -4,11 +4,13 @@ namespace ErsatzTV.FFmpeg.Filter; @@ -4,11 +4,13 @@ namespace ErsatzTV.FFmpeg.Filter;
public class TonemapFilter : BaseFilter
{
private readonly FFmpegState _ffmpegState;
private readonly FrameState _currentState;
private readonly IPixelFormat _desiredPixelFormat;
public TonemapFilter(FrameState currentState, IPixelFormat desiredPixelFormat)
public TonemapFilter(FFmpegState ffmpegState, FrameState currentState, IPixelFormat desiredPixelFormat)
{
_ffmpegState = ffmpegState;
_currentState = currentState;
_desiredPixelFormat = desiredPixelFormat;
}
@ -20,7 +22,7 @@ public class TonemapFilter : BaseFilter @@ -20,7 +22,7 @@ public class TonemapFilter : BaseFilter
string pixelFormat = _currentState.PixelFormat.Match(pf => pf.FFmpegName, () => string.Empty);
var tonemap =
$"zscale=transfer=linear,tonemap=linear,zscale=transfer=bt709,format={_desiredPixelFormat.FFmpegName}";
$"zscale=transfer=linear,tonemap={_ffmpegState.TonemapAlgorithm},zscale=transfer=bt709,format={_desiredPixelFormat.FFmpegName}";
if (_currentState.FrameDataLocation == FrameDataLocation.Hardware)
{

4
ErsatzTV.FFmpeg/Filter/Vaapi/TonemapVaapiFilter.cs

@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
namespace ErsatzTV.FFmpeg.Filter.Vaapi;
public class TonemapVaapiFilter : BaseFilter
public class TonemapVaapiFilter(FFmpegState ffmpegState) : BaseFilter
{
public override string Filter => "hwupload=derive_device=vaapi,hwmap=derive_device=opencl,tonemap_opencl,hwmap=derive_device=vaapi:reverse=1";
public override string Filter => $"hwupload=derive_device=vaapi,hwmap=derive_device=opencl,tonemap_opencl=tonemap={ffmpegState.TonemapAlgorithm},hwmap=derive_device=vaapi:reverse=1";
public override FrameState NextState(FrameState currentState) =>
currentState with

4
ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs

@ -752,14 +752,14 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -752,14 +752,14 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
{
if (ffmpegState.IsHdrTonemap)
{
var filter = new TonemapCudaFilter(pixelFormat);
var filter = new TonemapCudaFilter(ffmpegState, pixelFormat);
currentState = filter.NextState(currentState);
videoStream.ResetColorParams(ColorParams.Default);
videoInputFile.FilterSteps.Add(filter);
}
else
{
var filter = new TonemapFilter(currentState, pixelFormat);
var filter = new TonemapFilter(ffmpegState, currentState, pixelFormat);
currentState = filter.NextState(currentState);
videoStream.ResetColorParams(ColorParams.Default);
videoInputFile.FilterSteps.Add(filter);

2
ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs

@ -660,7 +660,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder @@ -660,7 +660,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder
}
else
{
var filter = new TonemapFilter(currentState, pixelFormat);
var filter = new TonemapFilter(ffmpegState, currentState, pixelFormat);
currentState = filter.NextState(currentState);
videoStream.ResetColorParams(ColorParams.Default);
videoInputFile.FilterSteps.Add(filter);

5
ErsatzTV.FFmpeg/Pipeline/SoftwarePipelineBuilder.cs

@ -105,7 +105,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase @@ -105,7 +105,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase
SetDeinterlace(videoInputFile, context, currentState);
currentState = SetScale(videoInputFile, videoStream, desiredState, currentState);
currentState = SetTonemap(videoInputFile, videoStream, desiredState, currentState);
currentState = SetTonemap(videoInputFile, videoStream, ffmpegState, desiredState, currentState);
currentState = SetPad(videoInputFile, videoStream, desiredState, currentState);
currentState = SetCrop(videoInputFile, desiredState, currentState);
SetStillImageLoop(videoInputFile, videoStream, ffmpegState, desiredState, pipelineSteps);
@ -321,6 +321,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase @@ -321,6 +321,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase
private static FrameState SetTonemap(
VideoInputFile videoInputFile,
VideoStream videoStream,
FFmpegState ffmpegState,
FrameState desiredState,
FrameState currentState)
{
@ -328,7 +329,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase @@ -328,7 +329,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase
{
foreach (IPixelFormat pixelFormat in desiredState.PixelFormat)
{
var tonemapStep = new TonemapFilter(currentState, pixelFormat);
var tonemapStep = new TonemapFilter(ffmpegState, currentState, pixelFormat);
currentState = tonemapStep.NextState(currentState);
videoStream.ResetColorParams(ColorParams.Default);
videoInputFile.FilterSteps.Add(tonemapStep);

4
ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

@ -638,14 +638,14 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder @@ -638,14 +638,14 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
{
if (ffmpegState.DecoderHardwareAccelerationMode == HardwareAccelerationMode.Vaapi && _ffmpegCapabilities.HasFilter(FFmpegKnownFilter.TonemapOpenCL))
{
var filter = new TonemapVaapiFilter();
var filter = new TonemapVaapiFilter(ffmpegState);
currentState = filter.NextState(currentState);
videoStream.ResetColorParams(ColorParams.Default);
videoInputFile.FilterSteps.Add(filter);
}
else
{
var filter = new TonemapFilter(currentState, pixelFormat);
var filter = new TonemapFilter(ffmpegState, currentState, pixelFormat);
currentState = filter.NextState(currentState);
videoStream.ResetColorParams(ColorParams.Default);
videoInputFile.FilterSteps.Add(filter);

11
ErsatzTV.FFmpeg/TonemapAlgorithm.cs

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
namespace ErsatzTV.FFmpeg;
public static class TonemapAlgorithm
{
public const string Linear = "linear";
public const string Clip = "clip";
public const string Gamma = "gamma";
public const string Reinhard = "reinhard";
public const string Mobius = "mobius";
public const string Hable = "hable";
}

5884
ErsatzTV.Infrastructure.MySql/Migrations/20250615001516_Add_FFmpegProfile_TonemapAlgorithm.Designer.cs generated

File diff suppressed because it is too large Load Diff

29
ErsatzTV.Infrastructure.MySql/Migrations/20250615001516_Add_FFmpegProfile_TonemapAlgorithm.cs

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

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

@ -637,6 +637,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -637,6 +637,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.Property<int>("ThreadCount")
.HasColumnType("int");
b.Property<int>("TonemapAlgorithm")
.HasColumnType("int");
b.Property<string>("VaapiDevice")
.HasColumnType("longtext");

5723
ErsatzTV.Infrastructure.Sqlite/Migrations/20250615001824_Add_FFmpegProfile_TonemapAlgorithm.Designer.cs generated

File diff suppressed because it is too large Load Diff

29
ErsatzTV.Infrastructure.Sqlite/Migrations/20250615001824_Add_FFmpegProfile_TonemapAlgorithm.cs

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

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

@ -606,6 +606,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -606,6 +606,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.Property<int>("ThreadCount")
.HasColumnType("INTEGER");
b.Property<int>("TonemapAlgorithm")
.HasColumnType("INTEGER");
b.Property<string>("VaapiDevice")
.HasColumnType("TEXT");

13
ErsatzTV/Pages/FFmpegEditor.razor

@ -154,6 +154,19 @@ @@ -154,6 +154,19 @@
<MudTextField Disabled="@(_model.HardwareAcceleration != HardwareAccelerationKind.Qsv)" Label="QSV Extra Hardware Frames" @bind-Value="_model.QsvExtraHardwareFrames" For="@(() => _model.QsvExtraHardwareFrames)"/>
</MudElement>
}
else
{
<MudElement HtmlTag="div" Class="mt-3">
<MudSelect Label="Tonemap Algorithm"
@bind-Value="_model.TonemapAlgorithm"
For="@(() => _model.TonemapAlgorithm)">
@foreach (FFmpegProfileTonemapAlgorithm algorithm in Enum.GetValues<FFmpegProfileTonemapAlgorithm>())
{
<MudSelectItem Value="@algorithm">@algorithm</MudSelectItem>
}
</MudSelect>
</MudElement>
}
<MudElement HtmlTag="div" Class="mt-3">
<MudCheckBox Label="Normalize Frame Rate" @bind-Value="@_model.NormalizeFramerate" For="@(() => _model.NormalizeFramerate)"/>
</MudElement>

4
ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

@ -38,6 +38,7 @@ public class FFmpegProfileEditViewModel @@ -38,6 +38,7 @@ public class FFmpegProfileEditViewModel
VideoPreset = viewModel.VideoPreset;
AllowBFrames = viewModel.AllowBFrames;
BitDepth = viewModel.BitDepth;
TonemapAlgorithm = viewModel.TonemapAlgorithm;
}
public int AudioBitrate { get; set; }
@ -65,6 +66,7 @@ public class FFmpegProfileEditViewModel @@ -65,6 +66,7 @@ public class FFmpegProfileEditViewModel
public string VideoPreset { get; set; }
public bool AllowBFrames { get; set; }
public FFmpegProfileBitDepth BitDepth { get; set; }
public FFmpegProfileTonemapAlgorithm TonemapAlgorithm { get; set; }
public CreateFFmpegProfile ToCreate() =>
new(
@ -84,6 +86,7 @@ public class FFmpegProfileEditViewModel @@ -84,6 +86,7 @@ public class FFmpegProfileEditViewModel
BitDepth,
VideoBitrate,
VideoBufferSize,
TonemapAlgorithm,
AudioFormat,
AudioBitrate,
AudioBufferSize,
@ -113,6 +116,7 @@ public class FFmpegProfileEditViewModel @@ -113,6 +116,7 @@ public class FFmpegProfileEditViewModel
BitDepth,
VideoBitrate,
VideoBufferSize,
TonemapAlgorithm,
AudioFormat,
AudioBitrate,
AudioBufferSize,

Loading…
Cancel
Save