Browse Source

normalize framerate (#122)

* normalize framerate

* simplify audio normalization settings
pull/123/head
Jason Dove 4 years ago committed by GitHub
parent
commit
4097288fed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .gitignore
  2. 7
      ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfile.cs
  3. 7
      ErsatzTV.Application/FFmpegProfiles/Commands/CreateFFmpegProfileHandler.cs
  4. 7
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfile.cs
  5. 5
      ErsatzTV.Application/FFmpegProfiles/Commands/UpdateFFmpegProfileHandler.cs
  6. 7
      ErsatzTV.Application/FFmpegProfiles/FFmpegProfileViewModel.cs
  7. 7
      ErsatzTV.Application/FFmpegProfiles/Mapper.cs
  8. 85
      ErsatzTV.Core.Tests/FFmpeg/FFmpegPlaybackSettingsServiceTests.cs
  9. 10
      ErsatzTV.Core/Domain/FFmpegProfile.cs
  10. 9
      ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs
  11. 2
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettings.cs
  12. 15
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs
  13. 8
      ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
  14. 3
      ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs
  15. 2
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  16. 1829
      ErsatzTV.Infrastructure/Migrations/20210331084648_Add_FFmpegProfile_FrameRate.Designer.cs
  17. 45
      ErsatzTV.Infrastructure/Migrations/20210331084648_Add_FFmpegProfile_FrameRate.cs
  18. 1826
      ErsatzTV.Infrastructure/Migrations/20210331092342_Remove_FFmpegProfile_NormalizeAudioCodec.Designer.cs
  19. 20
      ErsatzTV.Infrastructure/Migrations/20210331092342_Remove_FFmpegProfile_NormalizeAudioCodec.cs
  20. 11
      ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs
  21. 6
      ErsatzTV/Pages/FFmpeg.razor
  22. 11
      ErsatzTV/Pages/FFmpegEditor.razor
  23. 24
      ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

3
.gitignore vendored

@ -40,3 +40,6 @@ msbuild.wrn @@ -40,3 +40,6 @@ msbuild.wrn
core
scripts/generate-api-sdk/swagger.json
docker-compose.override.yml

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

@ -11,17 +11,16 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands @@ -11,17 +11,16 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
bool Transcode,
HardwareAccelerationKind HardwareAcceleration,
int ResolutionId,
bool NormalizeResolution,
bool NormalizeVideo,
string VideoCodec,
bool NormalizeVideoCodec,
int VideoBitrate,
int VideoBufferSize,
string AudioCodec,
bool NormalizeAudioCodec,
int AudioBitrate,
int AudioBufferSize,
int AudioVolume,
int AudioChannels,
int AudioSampleRate,
bool NormalizeAudio) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
bool NormalizeAudio,
string FrameRate) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
}

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

@ -43,19 +43,18 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands @@ -43,19 +43,18 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
Transcode = request.Transcode,
HardwareAcceleration = request.HardwareAcceleration,
ResolutionId = resolutionId,
NormalizeResolution = request.NormalizeResolution,
NormalizeVideo = request.NormalizeVideo,
VideoCodec = request.VideoCodec,
NormalizeVideoCodec = request.NormalizeVideoCodec,
VideoBitrate = request.VideoBitrate,
VideoBufferSize = request.VideoBufferSize,
AudioCodec = request.AudioCodec,
NormalizeAudioCodec = request.NormalizeAudioCodec,
AudioBitrate = request.AudioBitrate,
AudioBufferSize = request.AudioBufferSize,
AudioVolume = request.AudioVolume,
AudioChannels = request.AudioChannels,
AudioSampleRate = request.AudioSampleRate,
NormalizeAudio = request.NormalizeAudio
NormalizeAudio = request.NormalizeAudio,
FrameRate = request.FrameRate
});
private Validation<BaseError, string> ValidateName(CreateFFmpegProfile createFFmpegProfile) =>

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

@ -12,17 +12,16 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands @@ -12,17 +12,16 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
bool Transcode,
HardwareAccelerationKind HardwareAcceleration,
int ResolutionId,
bool NormalizeResolution,
bool NormalizeVideo,
string VideoCodec,
bool NormalizeVideoCodec,
int VideoBitrate,
int VideoBufferSize,
string AudioCodec,
bool NormalizeAudioCodec,
int AudioBitrate,
int AudioBufferSize,
int AudioVolume,
int AudioChannels,
int AudioSampleRate,
bool NormalizeAudio) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
bool NormalizeAudio,
string FrameRate) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
}

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

@ -37,19 +37,18 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands @@ -37,19 +37,18 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
p.Transcode = update.Transcode;
p.HardwareAcceleration = update.HardwareAcceleration;
p.ResolutionId = update.ResolutionId;
p.NormalizeResolution = update.NormalizeResolution;
p.NormalizeVideo = update.NormalizeVideo;
p.VideoCodec = update.VideoCodec;
p.NormalizeVideoCodec = update.NormalizeVideoCodec;
p.VideoBitrate = update.VideoBitrate;
p.VideoBufferSize = update.VideoBufferSize;
p.AudioCodec = update.AudioCodec;
p.NormalizeAudioCodec = update.NormalizeAudioCodec;
p.AudioBitrate = update.AudioBitrate;
p.AudioBufferSize = update.AudioBufferSize;
p.AudioVolume = update.AudioVolume;
p.AudioChannels = update.AudioChannels;
p.AudioSampleRate = update.AudioSampleRate;
p.NormalizeAudio = update.NormalizeAudio;
p.FrameRate = update.FrameRate;
await _ffmpegProfileRepository.Update(p);
return ProjectToViewModel(p);
}

7
ErsatzTV.Application/FFmpegProfiles/FFmpegProfileViewModel.cs

@ -10,17 +10,16 @@ namespace ErsatzTV.Application.FFmpegProfiles @@ -10,17 +10,16 @@ namespace ErsatzTV.Application.FFmpegProfiles
bool Transcode,
HardwareAccelerationKind HardwareAcceleration,
ResolutionViewModel Resolution,
bool NormalizeResolution,
bool NormalizeVideo,
string VideoCodec,
bool NormalizeVideoCodec,
int VideoBitrate,
int VideoBufferSize,
string AudioCodec,
bool NormalizeAudioCodec,
int AudioBitrate,
int AudioBufferSize,
int AudioVolume,
int AudioChannels,
int AudioSampleRate,
bool NormalizeAudio);
bool NormalizeAudio,
string FrameRate);
}

7
ErsatzTV.Application/FFmpegProfiles/Mapper.cs

@ -13,19 +13,18 @@ namespace ErsatzTV.Application.FFmpegProfiles @@ -13,19 +13,18 @@ namespace ErsatzTV.Application.FFmpegProfiles
profile.Transcode,
profile.HardwareAcceleration,
Project(profile.Resolution),
profile.NormalizeResolution,
profile.NormalizeVideo,
profile.VideoCodec,
profile.NormalizeVideoCodec,
profile.VideoBitrate,
profile.VideoBufferSize,
profile.AudioCodec,
profile.NormalizeAudioCodec,
profile.AudioBitrate,
profile.AudioBufferSize,
profile.AudioVolume,
profile.AudioChannels,
profile.AudioSampleRate,
profile.NormalizeAudio);
profile.NormalizeAudio,
profile.FrameRate);
private static ResolutionViewModel Project(Resolution resolution) =>
new(resolution.Id, resolution.Name, resolution.Width, resolution.Height);

85
ErsatzTV.Core.Tests/FFmpeg/FFmpegPlaybackSettingsServiceTests.cs

@ -163,9 +163,9 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -163,9 +163,9 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void ShouldNot_SetScaledSize_When_NotNormalizingResolution_ForTransportStream()
public void ShouldNot_SetScaledSize_When_NotNormalizingVideo_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with { NormalizeResolution = false };
FFmpegProfile ffmpegProfile = TestProfile() with { NormalizeVideo = false };
FFmpegPlaybackSettings actual = _calculator.CalculateSettings(
StreamingMode.TransportStream,
@ -184,7 +184,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -184,7 +184,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 }
};
@ -208,7 +208,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -208,7 +208,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 }
};
@ -232,7 +232,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -232,7 +232,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 }
};
@ -257,7 +257,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -257,7 +257,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 }
};
@ -282,7 +282,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -282,7 +282,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 }
};
@ -303,11 +303,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -303,11 +303,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_NotPadToDesiredResolution_When_NotNormalizingResolution()
public void Should_NotPadToDesiredResolution_When_NotNormalizingVideo()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeResolution = false,
NormalizeVideo = false,
Resolution = new Resolution { Width = 1920, Height = 1080 }
};
@ -332,9 +332,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -332,9 +332,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = false,
VideoCodec = "testCodec"
};
@ -357,13 +356,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -357,13 +356,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg
[Test]
public void
Should_SetDesiredVideoCodec_When_ContentIsCorrectSize_And_NormalizingWrongCodec_ForTransportStream()
Should_SetDesiredVideoCodec_When_ContentIsCorrectSize_And_NormalizingVideo_ForTransportStream()
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = true,
VideoCodec = "testCodec"
};
@ -387,13 +385,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -387,13 +385,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg
[Test]
public void
Should_SetCopyVideoCodec_When_ContentIsCorrectSize_And_NormalizingWrongCodec_ForHttpLiveStreaming()
Should_SetCopyVideoCodec_When_ContentIsCorrectSize_And_NormalizingVideo_ForHttpLiveStreaming()
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = true,
VideoCodec = "testCodec"
};
@ -420,9 +417,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -420,9 +417,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = true,
VideoCodec = "libx264"
};
@ -446,13 +442,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -446,13 +442,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg
[Test]
public void
Should_SetCopyVideoCodec_When_ContentIsCorrectSize_And_NotNormalizingWrongCodec_ForTransportStream()
Should_SetCopyVideoCodec_When_ContentIsCorrectSize_And_NotNormalizingVideo_ForTransportStream()
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = false,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = false,
VideoCodec = "libx264"
};
@ -479,9 +474,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -479,9 +474,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = false,
VideoBitrate = 2525
};
@ -503,13 +497,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -503,13 +497,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetVideoBitrate_When_ContentIsCorrectSize_And_NormalizingWrongCodec_ForTransportStream()
public void Should_SetVideoBitrate_When_ContentIsCorrectSize_And_NormalizingVideo_ForTransportStream()
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = true,
VideoBitrate = 2525
};
@ -536,9 +529,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -536,9 +529,8 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = false,
VideoBufferSize = 2525
};
@ -561,13 +553,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -561,13 +553,12 @@ namespace ErsatzTV.Core.Tests.FFmpeg
[Test]
public void
Should_SetVideoBufferSize_When_ContentIsCorrectSize_And_NormalizingWrongCodec_ForTransportStream()
Should_SetVideoBufferSize_When_ContentIsCorrectSize_And_NormalizingVideo_ForTransportStream()
{
var ffmpegProfile = new FFmpegProfile
{
NormalizeResolution = true,
NormalizeVideo = true,
Resolution = new Resolution { Width = 1920, Height = 1080 },
NormalizeVideoCodec = true,
VideoBufferSize = 2525
};
@ -594,7 +585,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -594,7 +585,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioCodec = "aac"
};
@ -613,11 +604,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -613,11 +604,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetCopyAudioCodec_When_NotNormalizingWrongCodec_ForTransportStream()
public void Should_SetCopyAudioCodec_When_NotNormalizingVideo_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = false,
NormalizeAudio = false,
AudioCodec = "aac"
};
@ -636,11 +627,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -636,11 +627,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetDesiredAudioCodec_When_NormalizingWrongCodec_ForTransportStream()
public void Should_SetDesiredAudioCodec_When_NormalizingVideo_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioCodec = "aac"
};
@ -659,11 +650,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -659,11 +650,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetCopyAudioCodec_When_NormalizingWrongCodec_ForHttpLiveStreaming()
public void Should_SetCopyAudioCodec_When_NormalizingVideo_ForHttpLiveStreaming()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioCodec = "aac"
};
@ -682,11 +673,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -682,11 +673,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetAudioBitrate_When_NormalizingWrongCodec_ForTransportStream()
public void Should_SetAudioBitrate_When_NormalizingVideo_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioBitrate = 2424
};
@ -705,11 +696,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -705,11 +696,11 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetAudioBufferSize_When_NormalizingWrongCodec_ForTransportStream()
public void Should_SetAudioBufferSize_When_NormalizingVideo_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioBufferSize = 2424
};
@ -732,7 +723,6 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -732,7 +723,6 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioCodec = "ac3",
AudioChannels = 6
@ -757,7 +747,6 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -757,7 +747,6 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioCodec = "ac3",
AudioSampleRate = 48
@ -778,11 +767,10 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -778,11 +767,10 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetAudioChannels_When_NormalizingWrongCodecAndAudio_ForTransportStream()
public void Should_SetAudioChannels_When_NormalizingVideoAndAudio_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioChannels = 6
};
@ -802,11 +790,10 @@ namespace ErsatzTV.Core.Tests.FFmpeg @@ -802,11 +790,10 @@ namespace ErsatzTV.Core.Tests.FFmpeg
}
[Test]
public void Should_SetAudioSampleRate_When_NormalizingWrongCodecAndAudio_ForTransportStream()
public void Should_SetAudioSampleRate_When_NormalizingVideoAndAudio_ForTransportStream()
{
FFmpegProfile ffmpegProfile = TestProfile() with
{
NormalizeAudioCodec = true,
NormalizeAudio = true,
AudioSampleRate = 48
};

10
ErsatzTV.Core/Domain/FFmpegProfile.cs

@ -9,13 +9,12 @@ @@ -9,13 +9,12 @@
public HardwareAccelerationKind HardwareAcceleration { get; set; }
public int ResolutionId { get; set; }
public Resolution Resolution { get; set; }
public bool NormalizeResolution { get; set; }
public string VideoCodec { get; set; }
public bool NormalizeVideoCodec { get; set; }
public bool NormalizeVideo { get; set; }
public int VideoBitrate { get; set; }
public int VideoBufferSize { get; set; }
public string FrameRate { get; set; }
public string AudioCodec { get; set; }
public bool NormalizeAudioCodec { get; set; }
public int AudioBitrate { get; set; }
public int AudioBufferSize { get; set; }
public int AudioVolume { get; set; }
@ -40,9 +39,8 @@ @@ -40,9 +39,8 @@
AudioVolume = 100,
AudioChannels = 2,
AudioSampleRate = 48,
NormalizeResolution = true,
NormalizeVideoCodec = true,
NormalizeAudioCodec = true,
NormalizeVideo = true,
FrameRate = "24",
NormalizeAudio = true
};
}

9
ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs

@ -13,6 +13,7 @@ namespace ErsatzTV.Core.FFmpeg @@ -13,6 +13,7 @@ namespace ErsatzTV.Core.FFmpeg
{
private Option<TimeSpan> _audioDuration = None;
private bool _deinterlace;
private Option<string> _frameRate = None;
private Option<HardwareAccelerationKind> _hardwareAccelerationKind = None;
private string _inputCodec;
private Option<IDisplaySize> _padToSize = None;
@ -54,6 +55,12 @@ namespace ErsatzTV.Core.FFmpeg @@ -54,6 +55,12 @@ namespace ErsatzTV.Core.FFmpeg
return this;
}
public FFmpegComplexFilterBuilder WithFrameRate(Option<string> frameRate)
{
_frameRate = frameRate;
return this;
}
public Option<FFmpegComplexFilter> Build(int videoStreamIndex, int audioStreamIndex)
{
var complexFilter = new StringBuilder();
@ -104,6 +111,8 @@ namespace ErsatzTV.Core.FFmpeg @@ -104,6 +111,8 @@ namespace ErsatzTV.Core.FFmpeg
}
}
_frameRate.IfSome(frameRate => filterQueue.Add($"fps=fps={frameRate}"));
_scaleToSize.IfSome(
size =>
{

2
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettings.cs

@ -16,7 +16,6 @@ namespace ErsatzTV.Core.FFmpeg @@ -16,7 +16,6 @@ namespace ErsatzTV.Core.FFmpeg
public Option<TimeSpan> StreamSeek { get; set; }
public Option<IDisplaySize> ScaledSize { get; set; }
public bool PadToDesiredResolution { get; set; }
public string ScalingAlgorithm => "fast_bilinear"; // TODO: from config, add tests
public string VideoCodec { get; set; }
public Option<int> VideoBitrate { get; set; }
public Option<int> VideoBufferSize { get; set; }
@ -27,5 +26,6 @@ namespace ErsatzTV.Core.FFmpeg @@ -27,5 +26,6 @@ namespace ErsatzTV.Core.FFmpeg
public Option<TimeSpan> AudioDuration { get; set; }
public string AudioCodec { get; set; }
public bool Deinterlace { get; set; }
public Option<string> FrameRate { get; set; }
}
}

15
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs

@ -81,11 +81,18 @@ namespace ErsatzTV.Core.FFmpeg @@ -81,11 +81,18 @@ namespace ErsatzTV.Core.FFmpeg
}
IDisplaySize sizeAfterScaling = result.ScaledSize.IfNone(version);
if (ffmpegProfile.NormalizeResolution && !sizeAfterScaling.IsSameSizeAs(ffmpegProfile.Resolution))
if (ffmpegProfile.NormalizeVideo && !sizeAfterScaling.IsSameSizeAs(ffmpegProfile.Resolution))
{
result.PadToDesiredResolution = true;
}
if (ffmpegProfile.NormalizeVideo)
{
result.FrameRate = string.IsNullOrWhiteSpace(ffmpegProfile.FrameRate)
? None
: Some(ffmpegProfile.FrameRate);
}
if (result.ScaledSize.IsSome || result.PadToDesiredResolution ||
NeedToNormalizeVideoCodec(ffmpegProfile, videoStream))
{
@ -141,7 +148,7 @@ namespace ErsatzTV.Core.FFmpeg @@ -141,7 +148,7 @@ namespace ErsatzTV.Core.FFmpeg
};
private static bool NeedToScale(FFmpegProfile ffmpegProfile, MediaVersion version) =>
ffmpegProfile.NormalizeResolution &&
ffmpegProfile.NormalizeVideo &&
IsIncorrectSize(ffmpegProfile.Resolution, version) ||
IsTooLarge(ffmpegProfile.Resolution, version) ||
IsOddSize(version);
@ -159,10 +166,10 @@ namespace ErsatzTV.Core.FFmpeg @@ -159,10 +166,10 @@ namespace ErsatzTV.Core.FFmpeg
version.Height % 2 == 1 || version.Width % 2 == 1;
private static bool NeedToNormalizeVideoCodec(FFmpegProfile ffmpegProfile, MediaStream videoStream) =>
ffmpegProfile.NormalizeVideoCodec && ffmpegProfile.VideoCodec != videoStream.Codec;
ffmpegProfile.NormalizeVideo && ffmpegProfile.VideoCodec != videoStream.Codec;
private static bool NeedToNormalizeAudioCodec(FFmpegProfile ffmpegProfile, MediaStream audioStream) =>
ffmpegProfile.NormalizeAudioCodec && ffmpegProfile.AudioCodec != audioStream.Codec;
ffmpegProfile.NormalizeAudio && ffmpegProfile.AudioCodec != audioStream.Codec;
private static IDisplaySize CalculateScaledSize(FFmpegProfile ffmpegProfile, MediaVersion version)
{

8
ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs

@ -229,7 +229,7 @@ namespace ErsatzTV.Core.FFmpeg @@ -229,7 +229,7 @@ namespace ErsatzTV.Core.FFmpeg
const string X = "x=(w-text_w)/2";
const string Y = "y=(h-text_h)/3*2";
string fontSize = text.Length > 60 ? "fontsize=40" : "fontsize=60";
string fontSize = text.Length > 80 ? "fontsize=30" : text.Length > 60 ? "fontsize=40" : "fontsize=60";
return WithFilterComplex(
$"[0:0]scale={desiredResolution.Width}:{desiredResolution.Height},drawtext={FONT_FILE}:{fontSize}:{FONT_COLOR}:{X}:{Y}:text='{text}'[v]",
@ -324,6 +324,12 @@ namespace ErsatzTV.Core.FFmpeg @@ -324,6 +324,12 @@ namespace ErsatzTV.Core.FFmpeg
return this;
}
public FFmpegProcessBuilder WithFrameRate(Option<string> frameRate)
{
_complexFilterBuilder = _complexFilterBuilder.WithFrameRate(frameRate);
return this;
}
public FFmpegProcessBuilder WithDeinterlace(bool deinterlace)
{
_complexFilterBuilder = _complexFilterBuilder.WithDeinterlace(deinterlace);

3
ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs

@ -48,7 +48,8 @@ namespace ErsatzTV.Core.FFmpeg @@ -48,7 +48,8 @@ namespace ErsatzTV.Core.FFmpeg
.WithFormatFlags(playbackSettings.FormatFlags)
.WithRealtimeOutput(playbackSettings.RealtimeOutput)
.WithSeek(playbackSettings.StreamSeek)
.WithInputCodec(path, playbackSettings.HardwareAcceleration, videoStream.Codec);
.WithInputCodec(path, playbackSettings.HardwareAcceleration, videoStream.Codec)
.WithFrameRate(playbackSettings.FrameRate);
playbackSettings.ScaledSize.Match(
scaledSize =>

2
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -235,7 +235,7 @@ namespace ErsatzTV.Core.Scheduling @@ -235,7 +235,7 @@ namespace ErsatzTV.Core.Scheduling
peekMediaItem =>
{
customGroup = true;
MediaVersion peekVersion = peekMediaItem switch
{
Movie m => m.MediaVersions.Head(),

1829
ErsatzTV.Infrastructure/Migrations/20210331084648_Add_FFmpegProfile_FrameRate.Designer.cs generated

File diff suppressed because it is too large Load Diff

45
ErsatzTV.Infrastructure/Migrations/20210331084648_Add_FFmpegProfile_FrameRate.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_FFmpegProfile_FrameRate : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
"NormalizeResolution",
"FFmpegProfile");
migrationBuilder.RenameColumn(
"NormalizeVideoCodec",
"FFmpegProfile",
"NormalizeVideo");
migrationBuilder.AddColumn<string>(
"FrameRate",
"FFmpegProfile",
"TEXT",
nullable: true,
defaultValue: "24");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
"FrameRate",
"FFmpegProfile");
migrationBuilder.RenameColumn(
"NormalizeVideo",
"FFmpegProfile",
"NormalizeVideoCodec");
migrationBuilder.AddColumn<bool>(
"NormalizeResolution",
"FFmpegProfile",
"INTEGER",
nullable: false,
defaultValue: false);
}
}
}

1826
ErsatzTV.Infrastructure/Migrations/20210331092342_Remove_FFmpegProfile_NormalizeAudioCodec.Designer.cs generated

File diff suppressed because it is too large Load Diff

20
ErsatzTV.Infrastructure/Migrations/20210331092342_Remove_FFmpegProfile_NormalizeAudioCodec.cs

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Remove_FFmpegProfile_NormalizeAudioCodec : Migration
{
protected override void Up(MigrationBuilder migrationBuilder) =>
migrationBuilder.DropColumn(
"NormalizeAudioCodec",
"FFmpegProfile");
protected override void Down(MigrationBuilder migrationBuilder) =>
migrationBuilder.AddColumn<bool>(
"NormalizeAudioCodec",
"FFmpegProfile",
"INTEGER",
nullable: false,
defaultValue: false);
}
}

11
ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

@ -240,6 +240,9 @@ namespace ErsatzTV.Infrastructure.Migrations @@ -240,6 +240,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int>("AudioVolume")
.HasColumnType("INTEGER");
b.Property<string>("FrameRate")
.HasColumnType("TEXT");
b.Property<int>("HardwareAcceleration")
.HasColumnType("INTEGER");
@ -249,13 +252,7 @@ namespace ErsatzTV.Infrastructure.Migrations @@ -249,13 +252,7 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<bool>("NormalizeAudio")
.HasColumnType("INTEGER");
b.Property<bool>("NormalizeAudioCodec")
.HasColumnType("INTEGER");
b.Property<bool>("NormalizeResolution")
.HasColumnType("INTEGER");
b.Property<bool>("NormalizeVideoCodec")
b.Property<bool>("NormalizeVideo")
.HasColumnType("INTEGER");
b.Property<int>("ResolutionId")

6
ErsatzTV/Pages/FFmpeg.razor

@ -74,17 +74,17 @@ @@ -74,17 +74,17 @@
@(context.Transcode ? "Yes" : "No")
</MudTd>
<MudTd DataLabel="Resolution">
<MudText Color="@(context.Transcode && context.NormalizeResolution ? Color.Tertiary : Color.Inherit)">
<MudText Color="@(context.Transcode && context.NormalizeVideo ? Color.Tertiary : Color.Inherit)">
@context.Resolution.Name
</MudText>
</MudTd>
<MudTd DataLabel="Video Codec">
<MudText Color="@(context.Transcode && context.NormalizeVideoCodec ? Color.Tertiary : Color.Inherit)">
<MudText Color="@(context.Transcode && context.NormalizeVideo ? Color.Tertiary : Color.Inherit)">
@context.VideoCodec
</MudText>
</MudTd>
<MudTd DataLabel="Audio Codec">
<MudText Color="@(context.Transcode && context.NormalizeAudioCodec ? Color.Tertiary : Color.Inherit)">
<MudText Color="@(context.Transcode && context.NormalizeAudio ? Color.Tertiary : Color.Inherit)">
@context.AudioCodec
</MudText>
</MudTd>

11
ErsatzTV/Pages/FFmpegEditor.razor

@ -58,6 +58,9 @@ @@ -58,6 +58,9 @@
}
</MudSelect>
</MudElement>
<MudElement HtmlTag="div" Class="mt-3">
<MudTextField Disabled="@(!_model.Transcode)" Label="Frame Rate" @bind-Value="_model.FrameRate" For="@(() => _model.FrameRate)" Adornment="Adornment.End" AdornmentText="fps"/>
</MudElement>
</MudItem>
<MudItem>
<MudText Typo="Typo.h6">Audio</MudText>
@ -80,13 +83,7 @@ @@ -80,13 +83,7 @@
</MudItem>
<MudItem>
<MudText Typo="Typo.h6">Normalization</MudText>
<MudCheckBox Disabled="@(!_model.Transcode)" Label="Normalize Resolution" @bind-Checked="@_model.NormalizeResolution" For="@(() => _model.NormalizeResolution)"/>
<MudElement HtmlTag="div" Class="mt-3">
<MudCheckBox Disabled="@(!_model.Transcode)" Label="Normalize Video Codec" @bind-Checked="@_model.NormalizeVideoCodec" For="@(() => _model.NormalizeVideoCodec)"/>
</MudElement>
<MudElement HtmlTag="div" Class="mt-3">
<MudCheckBox Disabled="@(!_model.Transcode)" Label="Normalize Audio Codec" @bind-Checked="@_model.NormalizeAudioCodec" For="@(() => _model.NormalizeAudioCodec)"/>
</MudElement>
<MudCheckBox Disabled="@(!_model.Transcode)" Label="Normalize Video" @bind-Checked="@_model.NormalizeVideo" For="@(() => _model.NormalizeVideo)"/>
<MudElement HtmlTag="div" Class="mt-3">
<MudCheckBox Disabled="@(!_model.Transcode)" Label="Normalize Audio" @bind-Checked="@_model.NormalizeAudio" For="@(() => _model.NormalizeAudio)"/>
</MudElement>

24
ErsatzTV/ViewModels/FFmpegProfileEditViewModel.cs

@ -22,9 +22,7 @@ namespace ErsatzTV.ViewModels @@ -22,9 +22,7 @@ namespace ErsatzTV.ViewModels
Id = viewModel.Id;
Name = viewModel.Name;
NormalizeAudio = viewModel.NormalizeAudio;
NormalizeAudioCodec = viewModel.NormalizeAudioCodec;
NormalizeResolution = viewModel.NormalizeResolution;
NormalizeVideoCodec = viewModel.NormalizeVideoCodec;
NormalizeVideo = viewModel.NormalizeVideo;
Resolution = viewModel.Resolution;
ThreadCount = viewModel.ThreadCount;
Transcode = viewModel.Transcode;
@ -32,6 +30,7 @@ namespace ErsatzTV.ViewModels @@ -32,6 +30,7 @@ namespace ErsatzTV.ViewModels
VideoBitrate = viewModel.VideoBitrate;
VideoBufferSize = viewModel.VideoBufferSize;
VideoCodec = viewModel.VideoCodec;
FrameRate = viewModel.FrameRate;
}
public int AudioBitrate { get; set; }
@ -43,9 +42,7 @@ namespace ErsatzTV.ViewModels @@ -43,9 +42,7 @@ namespace ErsatzTV.ViewModels
public int Id { get; set; }
public string Name { get; set; }
public bool NormalizeAudio { get; set; }
public bool NormalizeAudioCodec { get; set; }
public bool NormalizeResolution { get; set; }
public bool NormalizeVideoCodec { get; set; }
public bool NormalizeVideo { get; set; }
public ResolutionViewModel Resolution { get; set; }
public int ThreadCount { get; set; }
public bool Transcode { get; set; }
@ -53,6 +50,7 @@ namespace ErsatzTV.ViewModels @@ -53,6 +50,7 @@ namespace ErsatzTV.ViewModels
public int VideoBitrate { get; set; }
public int VideoBufferSize { get; set; }
public string VideoCodec { get; set; }
public string FrameRate { get; set; }
public CreateFFmpegProfile ToCreate() =>
new(
@ -61,19 +59,18 @@ namespace ErsatzTV.ViewModels @@ -61,19 +59,18 @@ namespace ErsatzTV.ViewModels
Transcode,
HardwareAcceleration,
Resolution.Id,
NormalizeResolution,
NormalizeVideo,
VideoCodec,
NormalizeVideoCodec,
VideoBitrate,
VideoBufferSize,
AudioCodec,
NormalizeAudioCodec,
AudioBitrate,
AudioBufferSize,
AudioVolume,
AudioChannels,
AudioSampleRate,
NormalizeAudio
NormalizeAudio,
FrameRate
);
public UpdateFFmpegProfile ToUpdate() =>
@ -84,19 +81,18 @@ namespace ErsatzTV.ViewModels @@ -84,19 +81,18 @@ namespace ErsatzTV.ViewModels
Transcode,
HardwareAcceleration,
Resolution.Id,
NormalizeResolution,
NormalizeVideo,
VideoCodec,
NormalizeVideoCodec,
VideoBitrate,
VideoBufferSize,
AudioCodec,
NormalizeAudioCodec,
AudioBitrate,
AudioBufferSize,
AudioVolume,
AudioChannels,
AudioSampleRate,
NormalizeAudio
NormalizeAudio,
FrameRate
);
}
}

Loading…
Cancel
Save