Browse Source

add h264 profile option to ffmpeg profile (#1686)

* add video profile for nvenc/software h264 encoders

* add h264 profile for all other encoders

* update changelog
pull/1687/head
Jason Dove 1 year ago committed by GitHub
parent
commit
c1d6ddcc57
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      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. 1
      ErsatzTV.Application/FFmpegProfiles/Mapper.cs
  8. 2
      ErsatzTV.Core/Domain/FFmpegProfile.cs
  9. 33
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  10. 19
      ErsatzTV.FFmpeg/Encoder/Amf/EncoderH264Amf.cs
  11. 19
      ErsatzTV.FFmpeg/Encoder/EncoderLibx264.cs
  12. 19
      ErsatzTV.FFmpeg/Encoder/Nvenc/EncoderH264Nvenc.cs
  13. 22
      ErsatzTV.FFmpeg/Encoder/Qsv/EncoderH264Qsv.cs
  14. 14
      ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs
  15. 19
      ErsatzTV.FFmpeg/Encoder/VideoToolbox/EncoderH264VideoToolbox.cs
  16. 1
      ErsatzTV.FFmpeg/Format/VideoProfile.cs
  17. 2
      ErsatzTV.FFmpeg/Pipeline/AmfPipelineBuilder.cs
  18. 6
      ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs
  19. 2
      ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs
  20. 2
      ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs
  21. 9
      ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs
  22. 2
      ErsatzTV.FFmpeg/Pipeline/VideoToolboxPipelineBuilder.cs
  23. 5593
      ErsatzTV.Infrastructure.MySql/Migrations/20240422144541_Add_FFmpegProfile_VideoProfile.Designer.cs
  24. 31
      ErsatzTV.Infrastructure.MySql/Migrations/20240422144541_Add_FFmpegProfile_VideoProfile.cs
  25. 3
      ErsatzTV.Infrastructure.MySql/Migrations/TvContextModelSnapshot.cs
  26. 5438
      ErsatzTV.Infrastructure.Sqlite/Migrations/20240422015853_Add_FFmpegProfile_VideoProfile.Designer.cs
  27. 30
      ErsatzTV.Infrastructure.Sqlite/Migrations/20240422015853_Add_FFmpegProfile_VideoProfile.cs
  28. 3
      ErsatzTV.Infrastructure.Sqlite/Migrations/TvContextModelSnapshot.cs
  29. 8
      ErsatzTV/Pages/FFmpegEditor.razor
  30. 4
      ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

2
CHANGELOG.md

@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -27,6 +27,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- ETV versions starting with v0.8.5-beta (using dotnet 8) store config data in `$HOME/Library/Application Support/ersatztv`
- If a dotnet 8 version of ETV has NOT been launched on MacOS, it will automatically migrate the config folder on startup
- If a dotnet 8 version of ETV *has* been launched on MacOS, a failing health check will display with instructions on how to resolve the config issue to restore data
- Add `Video Profile` setting to `FFmpeg Profile` editor when `h264` format is selected
### Fixed
- Fix some cases of 404s from Plex when files were replaced and scanning the library from ETV didn't help
@ -43,6 +44,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -43,6 +44,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- `Something.en.sdh.srt`
- Fix playback from Jellyfin 10.9 by allowing playlist HTTP HEAD requests
- Fix `HLS Segmenter V2` segment duration (previously 10s, now 4s)
- Fix `HLS Segmenter V2` error video generation
### Changed
- Use ffmpeg 7 in all docker images

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

@ -14,6 +14,7 @@ public record CreateFFmpegProfile( @@ -14,6 +14,7 @@ public record CreateFFmpegProfile(
int ResolutionId,
ScalingBehavior ScalingBehavior,
FFmpegProfileVideoFormat VideoFormat,
string VideoProfile,
FFmpegProfileBitDepth BitDepth,
int VideoBitrate,
int VideoBufferSize,

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

@ -54,6 +54,7 @@ public class CreateFFmpegProfileHandler : @@ -54,6 +54,7 @@ public class CreateFFmpegProfileHandler :
ResolutionId = resolutionId,
ScalingBehavior = request.ScalingBehavior,
VideoFormat = request.VideoFormat,
VideoProfile = request.VideoProfile,
BitDepth = request.BitDepth,
VideoBitrate = request.VideoBitrate,
VideoBufferSize = request.VideoBufferSize,

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

@ -15,6 +15,7 @@ public record UpdateFFmpegProfile( @@ -15,6 +15,7 @@ public record UpdateFFmpegProfile(
int ResolutionId,
ScalingBehavior ScalingBehavior,
FFmpegProfileVideoFormat VideoFormat,
string VideoProfile,
FFmpegProfileBitDepth BitDepth,
int VideoBitrate,
int VideoBufferSize,

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

@ -42,6 +42,7 @@ public class @@ -42,6 +42,7 @@ public class
p.ResolutionId = update.ResolutionId;
p.ScalingBehavior = update.ScalingBehavior;
p.VideoFormat = update.VideoFormat;
p.VideoProfile = update.VideoProfile;
// mpeg2video only supports 8-bit content
p.BitDepth = update.VideoFormat == FFmpegProfileVideoFormat.Mpeg2Video

1
ErsatzTV.Application/FFmpegProfiles/FFmpegProfileViewModel.cs

@ -15,6 +15,7 @@ public record FFmpegProfileViewModel( @@ -15,6 +15,7 @@ public record FFmpegProfileViewModel(
ResolutionViewModel Resolution,
ScalingBehavior ScalingBehavior,
FFmpegProfileVideoFormat VideoFormat,
string VideoProfile,
FFmpegProfileBitDepth BitDepth,
int VideoBitrate,
int VideoBufferSize,

1
ErsatzTV.Application/FFmpegProfiles/Mapper.cs

@ -17,6 +17,7 @@ internal static class Mapper @@ -17,6 +17,7 @@ internal static class Mapper
Resolutions.Mapper.ProjectToViewModel(profile.Resolution),
profile.ScalingBehavior,
profile.VideoFormat,
profile.VideoProfile,
profile.BitDepth,
profile.VideoBitrate,
profile.VideoBufferSize,

2
ErsatzTV.Core/Domain/FFmpegProfile.cs

@ -15,6 +15,7 @@ public record FFmpegProfile @@ -15,6 +15,7 @@ public record FFmpegProfile
public Resolution Resolution { get; set; }
public ScalingBehavior ScalingBehavior { get; set; }
public FFmpegProfileVideoFormat VideoFormat { get; set; }
public string VideoProfile { get; set; }
public FFmpegProfileBitDepth BitDepth { get; set; }
public int VideoBitrate { get; set; }
public int VideoBufferSize { get; set; }
@ -35,6 +36,7 @@ public record FFmpegProfile @@ -35,6 +36,7 @@ public record FFmpegProfile
ResolutionId = resolution.Id,
Resolution = resolution,
VideoFormat = FFmpegProfileVideoFormat.H264,
VideoProfile = "high",
AudioFormat = FFmpegProfileAudioFormat.Aac,
VideoBitrate = 2000,
VideoBufferSize = 4000,

33
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -304,6 +304,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -304,6 +304,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
Option<WatermarkInputFile> watermarkInputFile = GetWatermarkInputFile(watermarkOptions, maybeFadePoints);
string videoFormat = GetVideoFormat(playbackSettings);
Option<string> maybeVideoProfile = GetVideoProfile(videoFormat, channel.FFmpegProfile.VideoProfile);
HardwareAccelerationMode hwAccel = GetHardwareAccelerationMode(playbackSettings, fillerKind);
@ -343,7 +344,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -343,7 +344,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.RealtimeOutput,
fillerKind == FillerKind.Fallback,
videoFormat,
Optional(videoStream.Profile),
maybeVideoProfile,
Optional(playbackSettings.PixelFormat),
scaledSize,
paddedSize,
@ -444,11 +445,13 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -444,11 +445,13 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
Option<TimeSpan>.None,
AudioFilter.None);
var videoFormat = GetVideoFormat(playbackSettings);
var desiredState = new FrameState(
playbackSettings.RealtimeOutput,
false,
GetVideoFormat(playbackSettings),
VideoProfile.Main,
videoFormat,
GetVideoProfile(videoFormat, channel.FFmpegProfile.VideoProfile),
new PixelFormatYuv420P(),
new FrameSize(desiredResolution.Width, desiredResolution.Height),
new FrameSize(desiredResolution.Width, desiredResolution.Height),
@ -460,9 +463,16 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -460,9 +463,16 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.VideoTrackTimeScale,
playbackSettings.Deinterlace);
OutputFormatKind outputFormat = channel.StreamingMode == StreamingMode.HttpLiveStreamingSegmenter
? OutputFormatKind.Hls
: OutputFormatKind.MpegTs;
OutputFormatKind outputFormat = OutputFormatKind.MpegTs;
switch (channel.StreamingMode)
{
case StreamingMode.HttpLiveStreamingSegmenter:
outputFormat = OutputFormatKind.Hls;
break;
case StreamingMode.HttpLiveStreamingSegmenterV2:
outputFormat = OutputFormatKind.Nut;
break;
}
Option<string> hlsPlaylistPath = outputFormat == OutputFormatKind.Hls
? Path.Combine(FileSystemLayout.TranscodeFolder, channel.Number, "live.m3u8")
@ -646,6 +656,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -646,6 +656,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
Option<WatermarkInputFile> watermarkInputFile = Option<WatermarkInputFile>.None;
string videoFormat = GetVideoFormat(playbackSettings);
Option<string> maybeVideoProfile = GetVideoProfile(videoFormat, channel.FFmpegProfile.VideoProfile);
HardwareAccelerationMode hwAccel = GetHardwareAccelerationMode(playbackSettings, FillerKind.None);
@ -664,7 +675,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -664,7 +675,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
playbackSettings.RealtimeOutput,
true,
videoFormat,
Option<string>.None,
maybeVideoProfile,
Optional(playbackSettings.PixelFormat),
resolution,
resolution,
@ -980,6 +991,14 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService @@ -980,6 +991,14 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
_ => throw new ArgumentOutOfRangeException($"unexpected video format {playbackSettings.VideoFormat}")
};
private static Option<string> GetVideoProfile(string videoFormat, string videoProfile) =>
(videoFormat, videoProfile.ToLowerInvariant()) switch
{
(VideoFormat.H264, VideoProfile.Main) => VideoProfile.Main,
(VideoFormat.H264, VideoProfile.High) => VideoProfile.High,
_ => Option<string>.None
};
private static HardwareAccelerationMode GetHardwareAccelerationMode(
FFmpegPlaybackSettings playbackSettings,
FillerKind fillerKind) =>

19
ErsatzTV.FFmpeg/Encoder/Amf/EncoderH264Amf.cs

@ -2,10 +2,27 @@ @@ -2,10 +2,27 @@
namespace ErsatzTV.FFmpeg.Encoder.Amf;
public class EncoderH264Amf : EncoderBase
public class EncoderH264Amf(Option<string> maybeVideoProfile) : EncoderBase
{
public override string Name => "h264_amf";
public override StreamKind Kind => StreamKind.Video;
public override string[] OutputOptions
{
get
{
foreach (string videoProfile in maybeVideoProfile)
{
return
[
"-c:v", Name,
"-profile:v", videoProfile.ToLowerInvariant(),
];
}
return base.OutputOptions;
}
}
public override FrameState NextState(FrameState currentState) => currentState with
{

19
ErsatzTV.FFmpeg/Encoder/EncoderLibx264.cs

@ -2,10 +2,27 @@ @@ -2,10 +2,27 @@
namespace ErsatzTV.FFmpeg.Encoder;
public class EncoderLibx264 : EncoderBase
public class EncoderLibx264(Option<string> maybeVideoProfile) : EncoderBase
{
public override string Name => "libx264";
public override StreamKind Kind => StreamKind.Video;
public override string[] OutputOptions
{
get
{
foreach (string videoProfile in maybeVideoProfile)
{
return
[
"-c:v", Name,
"-profile:v", videoProfile.ToLowerInvariant()
];
}
return base.OutputOptions;
}
}
public override FrameState NextState(FrameState currentState) =>
currentState with { VideoFormat = VideoFormat.H264 };

19
ErsatzTV.FFmpeg/Encoder/Nvenc/EncoderH264Nvenc.cs

@ -2,11 +2,28 @@ @@ -2,11 +2,28 @@
namespace ErsatzTV.FFmpeg.Encoder.Nvenc;
public class EncoderH264Nvenc : EncoderBase
public class EncoderH264Nvenc(Option<string> maybeVideoProfile) : EncoderBase
{
public override string Name => "h264_nvenc";
public override StreamKind Kind => StreamKind.Video;
public override string[] OutputOptions
{
get
{
foreach (string videoProfile in maybeVideoProfile)
{
return
[
"-c:v", Name,
"-profile:v", videoProfile.ToLowerInvariant(),
];
}
return base.OutputOptions;
}
}
public override FrameState NextState(FrameState currentState) => currentState with
{
VideoFormat = VideoFormat.H264

22
ErsatzTV.FFmpeg/Encoder/Qsv/EncoderH264Qsv.cs

@ -2,13 +2,29 @@ @@ -2,13 +2,29 @@
namespace ErsatzTV.FFmpeg.Encoder.Qsv;
public class EncoderH264Qsv : EncoderBase
public class EncoderH264Qsv(Option<string> maybeVideoProfile) : EncoderBase
{
public override string Name => "h264_qsv";
public override StreamKind Kind => StreamKind.Video;
public override string[] OutputOptions =>
new[] { "-c:v", "h264_qsv", "-low_power", "0", "-look_ahead", "0" };
public override string[] OutputOptions
{
get
{
foreach (string videoProfile in maybeVideoProfile)
{
return
[
"-c:v", Name,
"-low_power", "0",
"-look_ahead", "0",
"-profile:v", videoProfile.ToLowerInvariant(),
];
}
return ["-c:v", Name, "-low_power", "0", "-look_ahead", "0"];
}
}
public override FrameState NextState(FrameState currentState) => currentState with
{

14
ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs

@ -2,12 +2,8 @@ @@ -2,12 +2,8 @@
namespace ErsatzTV.FFmpeg.Encoder.Vaapi;
public class EncoderH264Vaapi : EncoderBase
public class EncoderH264Vaapi(Option<string> maybeVideoProfile, RateControlMode rateControlMode) : EncoderBase
{
private readonly RateControlMode _rateControlMode;
public EncoderH264Vaapi(RateControlMode rateControlMode) => _rateControlMode = rateControlMode;
public override string Name => "h264_vaapi";
public override StreamKind Kind => StreamKind.Video;
@ -18,7 +14,7 @@ public class EncoderH264Vaapi : EncoderBase @@ -18,7 +14,7 @@ public class EncoderH264Vaapi : EncoderBase
{
var result = new List<string>(base.OutputOptions);
if (_rateControlMode == RateControlMode.CQP)
if (rateControlMode == RateControlMode.CQP)
{
result.Add("-rc_mode");
result.Add("1");
@ -26,6 +22,12 @@ public class EncoderH264Vaapi : EncoderBase @@ -26,6 +22,12 @@ public class EncoderH264Vaapi : EncoderBase
result.Add("-sei");
result.Add("-a53_cc");
foreach (string videoProfile in maybeVideoProfile)
{
result.Add("-profile:v");
result.Add(videoProfile.ToLowerInvariant());
}
return result.ToArray();
}

19
ErsatzTV.FFmpeg/Encoder/VideoToolbox/EncoderH264VideoToolbox.cs

@ -2,10 +2,27 @@ @@ -2,10 +2,27 @@
namespace ErsatzTV.FFmpeg.Encoder.VideoToolbox;
public class EncoderH264VideoToolbox : EncoderBase
public class EncoderH264VideoToolbox(Option<string> maybeVideoProfile) : EncoderBase
{
public override string Name => "h264_videotoolbox";
public override StreamKind Kind => StreamKind.Video;
public override string[] OutputOptions
{
get
{
foreach (string videoProfile in maybeVideoProfile)
{
return
[
"-c:v", Name,
"-profile:v", videoProfile.ToLowerInvariant(),
];
}
return base.OutputOptions;
}
}
public override FrameState NextState(FrameState currentState) => currentState with
{

1
ErsatzTV.FFmpeg/Format/VideoProfile.cs

@ -3,4 +3,5 @@ namespace ErsatzTV.FFmpeg.Format; @@ -3,4 +3,5 @@ namespace ErsatzTV.FFmpeg.Format;
public static class VideoProfile
{
public const string Main = "main";
public const string High = "high";
}

2
ErsatzTV.FFmpeg/Pipeline/AmfPipelineBuilder.cs

@ -80,7 +80,7 @@ public class AmfPipelineBuilder : SoftwarePipelineBuilder @@ -80,7 +80,7 @@ public class AmfPipelineBuilder : SoftwarePipelineBuilder
(HardwareAccelerationMode.Amf, VideoFormat.Hevc) =>
new EncoderHevcAmf(),
(HardwareAccelerationMode.Amf, VideoFormat.H264) =>
new EncoderH264Amf(),
new EncoderH264Amf(desiredState.VideoProfile),
_ => GetSoftwareEncoder(ffmpegState, currentState, desiredState)
};

6
ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs

@ -249,8 +249,10 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -249,8 +249,10 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
Option<IEncoder> maybeEncoder =
(ffmpegState.EncoderHardwareAccelerationMode, desiredState.VideoFormat) switch
{
(HardwareAccelerationMode.Nvenc, VideoFormat.Hevc) => new EncoderHevcNvenc(_hardwareCapabilities),
(HardwareAccelerationMode.Nvenc, VideoFormat.H264) => new EncoderH264Nvenc(),
(HardwareAccelerationMode.Nvenc, VideoFormat.Hevc) =>
new EncoderHevcNvenc(_hardwareCapabilities),
(HardwareAccelerationMode.Nvenc, VideoFormat.H264) =>
new EncoderH264Nvenc(desiredState.VideoProfile),
(_, _) => GetSoftwareEncoder(ffmpegState, currentState, desiredState)
};

2
ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs

@ -575,7 +575,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder @@ -575,7 +575,7 @@ public abstract class PipelineBuilderBase : IPipelineBuilder
{
VideoFormat.Hevc => new EncoderLibx265(
currentState with { FrameDataLocation = FrameDataLocation.Software }),
VideoFormat.H264 => new EncoderLibx264(),
VideoFormat.H264 => new EncoderLibx264(desiredState.VideoProfile),
VideoFormat.Mpeg2Video => new EncoderMpeg2Video(),
VideoFormat.Copy => new EncoderCopyVideo(),

2
ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs

@ -212,7 +212,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder @@ -212,7 +212,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder
(ffmpegState.EncoderHardwareAccelerationMode, desiredState.VideoFormat) switch
{
(HardwareAccelerationMode.Qsv, VideoFormat.Hevc) => new EncoderHevcQsv(),
(HardwareAccelerationMode.Qsv, VideoFormat.H264) => new EncoderH264Qsv(),
(HardwareAccelerationMode.Qsv, VideoFormat.H264) => new EncoderH264Qsv(desiredState.VideoProfile),
(HardwareAccelerationMode.Qsv, VideoFormat.Mpeg2Video) => new EncoderMpeg2Qsv(),
(_, _) => GetSoftwareEncoder(ffmpegState, currentState, desiredState)

9
ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

@ -230,9 +230,12 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder @@ -230,9 +230,12 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
Option<IEncoder> maybeEncoder =
(ffmpegState.EncoderHardwareAccelerationMode, desiredState.VideoFormat) switch
{
(HardwareAccelerationMode.Vaapi, VideoFormat.Hevc) => new EncoderHevcVaapi(rateControlMode),
(HardwareAccelerationMode.Vaapi, VideoFormat.H264) => new EncoderH264Vaapi(rateControlMode),
(HardwareAccelerationMode.Vaapi, VideoFormat.Mpeg2Video) => new EncoderMpeg2Vaapi(rateControlMode),
(HardwareAccelerationMode.Vaapi, VideoFormat.Hevc) =>
new EncoderHevcVaapi(rateControlMode),
(HardwareAccelerationMode.Vaapi, VideoFormat.H264) =>
new EncoderH264Vaapi(desiredState.VideoProfile, rateControlMode),
(HardwareAccelerationMode.Vaapi, VideoFormat.Mpeg2Video) =>
new EncoderMpeg2Vaapi(rateControlMode),
(_, _) => GetSoftwareEncoder(ffmpegState, currentState, desiredState)
};

2
ErsatzTV.FFmpeg/Pipeline/VideoToolboxPipelineBuilder.cs

@ -103,7 +103,7 @@ public class VideoToolboxPipelineBuilder : SoftwarePipelineBuilder @@ -103,7 +103,7 @@ public class VideoToolboxPipelineBuilder : SoftwarePipelineBuilder
(HardwareAccelerationMode.VideoToolbox, VideoFormat.Hevc) =>
new EncoderHevcVideoToolbox(desiredState.BitDepth),
(HardwareAccelerationMode.VideoToolbox, VideoFormat.H264) =>
new EncoderH264VideoToolbox(),
new EncoderH264VideoToolbox(desiredState.VideoProfile),
_ => GetSoftwareEncoder(ffmpegState, currentState, desiredState)
};

5593
ErsatzTV.Infrastructure.MySql/Migrations/20240422144541_Add_FFmpegProfile_VideoProfile.Designer.cs generated

File diff suppressed because it is too large Load Diff

31
ErsatzTV.Infrastructure.MySql/Migrations/20240422144541_Add_FFmpegProfile_VideoProfile.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.MySql.Migrations
{
/// <inheritdoc />
public partial class Add_FFmpegProfile_VideoProfile : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "VideoProfile",
table: "FFmpegProfile",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.Sql("UPDATE FFmpegProfile SET VideoProfile = 'high'");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "VideoProfile",
table: "FFmpegProfile");
}
}
}

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

@ -643,6 +643,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations @@ -643,6 +643,9 @@ namespace ErsatzTV.Infrastructure.MySql.Migrations
b.Property<int>("VideoFormat")
.HasColumnType("int");
b.Property<string>("VideoProfile")
.HasColumnType("longtext");
b.HasKey("Id");
b.HasIndex("ResolutionId");

5438
ErsatzTV.Infrastructure.Sqlite/Migrations/20240422015853_Add_FFmpegProfile_VideoProfile.Designer.cs generated

File diff suppressed because it is too large Load Diff

30
ErsatzTV.Infrastructure.Sqlite/Migrations/20240422015853_Add_FFmpegProfile_VideoProfile.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Sqlite.Migrations
{
/// <inheritdoc />
public partial class Add_FFmpegProfile_VideoProfile : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "VideoProfile",
table: "FFmpegProfile",
type: "TEXT",
nullable: true);
migrationBuilder.Sql("UPDATE FFmpegProfile SET VideoProfile = 'high'");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "VideoProfile",
table: "FFmpegProfile");
}
}
}

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

@ -612,6 +612,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations @@ -612,6 +612,9 @@ namespace ErsatzTV.Infrastructure.Sqlite.Migrations
b.Property<int>("VideoFormat")
.HasColumnType("INTEGER");
b.Property<string>("VideoProfile")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ResolutionId");

8
ErsatzTV/Pages/FFmpegEditor.razor

@ -5,6 +5,7 @@ @@ -5,6 +5,7 @@
@using ErsatzTV.Application.FFmpegProfiles
@using System.Runtime.InteropServices
@using ErsatzTV.Core.FFmpeg
@using ErsatzTV.FFmpeg.Format
@implements IDisposable
@inject NavigationManager _navigationManager
@inject ILogger<FFmpegEditor> _logger
@ -57,6 +58,13 @@ @@ -57,6 +58,13 @@
<MudSelectItem Value="@FFmpegProfileVideoFormat.Hevc">hevc</MudSelectItem>
<MudSelectItem Value="@FFmpegProfileVideoFormat.Mpeg2Video">mpeg-2</MudSelectItem>
</MudSelect>
<MudSelect Label="Profile"
@bind-Value="_model.VideoProfile"
For="@(() => _model.VideoProfile)"
Disabled="@(_model.VideoFormat != FFmpegProfileVideoFormat.H264 || (_model.HardwareAcceleration != HardwareAccelerationKind.Nvenc && _model.HardwareAcceleration != HardwareAccelerationKind.None))">
<MudSelectItem Value="@VideoProfile.Main">main</MudSelectItem>
<MudSelectItem Value="@VideoProfile.High">high</MudSelectItem>
</MudSelect>
<MudSelect Label="Bit Depth" @bind-Value="_model.BitDepth" For="@(() => _model.BitDepth)">
<MudSelectItem Value="@FFmpegProfileBitDepth.EightBit">8-bit</MudSelectItem>
<MudSelectItem Value="@FFmpegProfileBitDepth.TenBit">10-bit</MudSelectItem>

4
ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

@ -33,6 +33,7 @@ public class FFmpegProfileEditViewModel @@ -33,6 +33,7 @@ public class FFmpegProfileEditViewModel
VideoBitrate = viewModel.VideoBitrate;
VideoBufferSize = viewModel.VideoBufferSize;
VideoFormat = viewModel.VideoFormat;
VideoProfile = viewModel.VideoProfile;
BitDepth = viewModel.BitDepth;
}
@ -56,6 +57,7 @@ public class FFmpegProfileEditViewModel @@ -56,6 +57,7 @@ public class FFmpegProfileEditViewModel
public int VideoBitrate { get; set; }
public int VideoBufferSize { get; set; }
public FFmpegProfileVideoFormat VideoFormat { get; set; }
public string VideoProfile { get; set; }
public FFmpegProfileBitDepth BitDepth { get; set; }
public CreateFFmpegProfile ToCreate() =>
@ -69,6 +71,7 @@ public class FFmpegProfileEditViewModel @@ -69,6 +71,7 @@ public class FFmpegProfileEditViewModel
Resolution.Id,
ScalingBehavior,
VideoFormat,
VideoProfile,
BitDepth,
VideoBitrate,
VideoBufferSize,
@ -94,6 +97,7 @@ public class FFmpegProfileEditViewModel @@ -94,6 +97,7 @@ public class FFmpegProfileEditViewModel
Resolution.Id,
ScalingBehavior,
VideoFormat,
VideoProfile,
BitDepth,
VideoBitrate,
VideoBufferSize,

Loading…
Cancel
Save