normalize framerate (#122)

* normalize framerate

* simplify audio normalization settings
This commit is contained in:
Jason Dove
2021-03-31 09:34:52 +00:00
committed by GitHub
parent 90f775aab4
commit 4097288fed
23 changed files with 3832 additions and 117 deletions
+4 -6
View File
@@ -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 @@
AudioVolume = 100,
AudioChannels = 2,
AudioSampleRate = 48,
NormalizeResolution = true,
NormalizeVideoCodec = true,
NormalizeAudioCodec = true,
NormalizeVideo = true,
FrameRate = "24",
NormalizeAudio = true
};
}
@@ -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
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
}
}
_frameRate.IfSome(frameRate => filterQueue.Add($"fps=fps={frameRate}"));
_scaleToSize.IfSome(
size =>
{
@@ -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
public Option<TimeSpan> AudioDuration { get; set; }
public string AudioCodec { get; set; }
public bool Deinterlace { get; set; }
public Option<string> FrameRate { get; set; }
}
}
@@ -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
};
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
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)
{
+7 -1
View File
@@ -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
return this;
}
public FFmpegProcessBuilder WithFrameRate(Option<string> frameRate)
{
_complexFilterBuilder = _complexFilterBuilder.WithFrameRate(frameRate);
return this;
}
public FFmpegProcessBuilder WithDeinterlace(bool deinterlace)
{
_complexFilterBuilder = _complexFilterBuilder.WithDeinterlace(deinterlace);
+2 -1
View File
@@ -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 =>
+1 -1
View File
@@ -235,7 +235,7 @@ namespace ErsatzTV.Core.Scheduling
peekMediaItem =>
{
customGroup = true;
MediaVersion peekVersion = peekMediaItem switch
{
Movie m => m.MediaVersions.Head(),