From e76ebdcbe8594acf3bc6f8d1135854d25d963a5e Mon Sep 17 00:00:00 2001 From: Gleb Moskalenko Date: Tue, 21 Jun 2022 17:35:19 +0300 Subject: [PATCH] Add pad video filter --- FFMpegCore.Test/ArgumentBuilderTest.cs | 40 ++++++++++++ FFMpegCore/FFMpeg/Arguments/PadArgument.cs | 65 +++++++++++++++++++ .../FFMpeg/Arguments/VideoFiltersArgument.cs | 1 + 3 files changed, 106 insertions(+) create mode 100644 FFMpegCore/FFMpeg/Arguments/PadArgument.cs diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs index 906a87b..1c9cb5c 100644 --- a/FFMpegCore.Test/ArgumentBuilderTest.cs +++ b/FFMpegCore.Test/ArgumentBuilderTest.cs @@ -495,5 +495,45 @@ public void Builder_BuildString_Audible_AAXC_Decryption() Assert.AreEqual("-audible_key 123 -audible_iv 456 -i \"input.aaxc\" -map_metadata 0 -id3v2_version 3 -vn -c:a copy \"output.m4b\" -y", str); } + + [TestMethod] + public void Builder_BuildString_PadFilter() + { + var str = FFMpegArguments + .FromFileInput("input.mp4") + .OutputToFile("output.mp4", false, opt => opt + .WithVideoFilters(filterOptions => filterOptions + .Pad(PadOptions + .Create("max(iw,ih)", "ow") + .WithParameter("x", "(ow-iw)/2") + .WithParameter("y", "(oh-ih)/2") + .WithParameter("color", "violet") + .WithParameter("eval", "frame")))) + .Arguments; + + Assert.AreEqual( + "-i \"input.mp4\" -vf \"pad=width=max(iw\\,ih):height=ow:x=(ow-iw)/2:y=(oh-ih)/2:color=violet:eval=frame\" \"output.mp4\"", + str); + } + + [TestMethod] + public void Builder_BuildString_PadFilter_Alt() + { + var str = FFMpegArguments + .FromFileInput("input.mp4") + .OutputToFile("output.mp4", false, opt => opt + .WithVideoFilters(filterOptions => filterOptions + .Pad(PadOptions + .Create("4/3") + .WithParameter("x", "(ow-iw)/2") + .WithParameter("y", "(oh-ih)/2") + .WithParameter("color", "violet") + .WithParameter("eval", "frame")))) + .Arguments; + + Assert.AreEqual( + "-i \"input.mp4\" -vf \"pad=aspect=4/3:x=(ow-iw)/2:y=(oh-ih)/2:color=violet:eval=frame\" \"output.mp4\"", + str); + } } } \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Arguments/PadArgument.cs b/FFMpegCore/FFMpeg/Arguments/PadArgument.cs new file mode 100644 index 0000000..000c369 --- /dev/null +++ b/FFMpegCore/FFMpeg/Arguments/PadArgument.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FFMpegCore.Extend; + +namespace FFMpegCore.Arguments +{ + public class PadArgument : IVideoFilterArgument + { + private readonly PadOptions _options; + + public PadArgument(PadOptions options) + { + _options = options; + } + + public string Key => "pad"; + public string Value => _options.TextInternal; + + } + + public class PadOptions + { + public readonly Dictionary Parameters = new Dictionary(); + + internal string TextInternal => string.Join(":", Parameters.Select(parameter => parameter.FormatArgumentPair(true))); + + public static PadOptions Create(string? width, string? height) + { + return new PadOptions(width, height); + } + + public static PadOptions Create(string aspectRatio) + { + return new PadOptions(aspectRatio); + } + + public PadOptions WithParameter(string key, string value) + { + Parameters.Add(key, value); + return this; + } + + private PadOptions(string? width, string? height) + { + if (width == null && height == null) + { + throw new Exception("At least one of the parameters must be not null"); + } + if (width != null) + { + Parameters.Add("width", width); + } + if (height != null) + { + Parameters.Add("height", height); + } + } + + private PadOptions(string aspectRatio) + { + Parameters.Add("aspect", aspectRatio); + } + } +} diff --git a/FFMpegCore/FFMpeg/Arguments/VideoFiltersArgument.cs b/FFMpegCore/FFMpeg/Arguments/VideoFiltersArgument.cs index c49803f..793260f 100644 --- a/FFMpegCore/FFMpeg/Arguments/VideoFiltersArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/VideoFiltersArgument.cs @@ -53,6 +53,7 @@ public class VideoFilterOptions public VideoFilterOptions HardBurnSubtitle(SubtitleHardBurnOptions subtitleHardBurnOptions) => WithArgument(new SubtitleHardBurnArgument(subtitleHardBurnOptions)); public VideoFilterOptions BlackDetect(double minimumDuration = 2.0, double pictureBlackRatioThreshold = 0.98, double pixelBlackThreshold = 0.1) => WithArgument(new BlackDetectArgument(minimumDuration, pictureBlackRatioThreshold, pixelBlackThreshold)); public VideoFilterOptions BlackFrame(int amount = 98, int threshold = 32) => WithArgument(new BlackFrameArgument(amount, threshold)); + public VideoFilterOptions Pad(PadOptions padOptions) => WithArgument(new PadArgument(padOptions)); private VideoFilterOptions WithArgument(IVideoFilterArgument argument) {