From b0c2a7ea92ebc867945a69475ce244f03bf29682 Mon Sep 17 00:00:00 2001 From: Vlad Jerca Date: Fri, 8 Feb 2019 18:17:05 +0200 Subject: [PATCH] FFMpegCore: use the argument builder in the ffmpeg methods Former-commit-id: 3729d65e2473af49c57648f3cee7c03817bda3da --- FFMpegCore.Test/ArgumentBuilderTests.cs | 52 +++--- FFMpegCore.Test/VideoTest.cs | 12 +- .../Arguments/DisableChannelArgument.cs | 27 +++ .../FFMPEG/Arguments/FFArgumentBuilder.cs | 59 +----- .../FFMPEG/Arguments/IArgumentBuilder.cs | 2 - FFMpegCore/FFMPEG/Arguments/InputArgument.cs | 12 +- FFMpegCore/FFMPEG/Arguments/OutputArgument.cs | 8 +- FFMpegCore/FFMPEG/Arguments/SeekArgument.cs | 4 +- FFMpegCore/FFMPEG/Arguments/SizeArgument.cs | 2 +- FFMpegCore/FFMPEG/FFMpeg.cs | 172 +++++++++--------- 10 files changed, 158 insertions(+), 192 deletions(-) create mode 100644 FFMpegCore/FFMPEG/Arguments/DisableChannelArgument.cs diff --git a/FFMpegCore.Test/ArgumentBuilderTests.cs b/FFMpegCore.Test/ArgumentBuilderTests.cs index 080eef4..97e32af 100644 --- a/FFMpegCore.Test/ArgumentBuilderTests.cs +++ b/FFMpegCore.Test/ArgumentBuilderTests.cs @@ -25,13 +25,12 @@ public ArgumentBuilderTests() : base() private string GetArgumentsString(params Argument[] args) { var container = new ArgumentsContainer(); - container.Add(new OutputArgument("output.mp4")); container.Add(new InputArgument("input.mp4")); - foreach (var a in args) { container.Add(a); } + container.Add(new OutputArgument("output.mp4")); return builder.BuildArguments(container); } @@ -42,7 +41,7 @@ public void Builder_BuildString_IO_1() { var str = GetArgumentsString(); - Assert.IsTrue(str == "-i \"input.mp4\" \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" \"output.mp4\""); } [TestMethod] @@ -50,15 +49,14 @@ public void Builder_BuildString_Scale() { var str = GetArgumentsString(new ScaleArgument(VideoSize.Hd)); - Assert.IsTrue(str == "-i \"input.mp4\" -vf scale=-1:720 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -vf scale=-1:720 \"output.mp4\""); } [TestMethod] public void Builder_BuildString_AudioCodec() { var str = GetArgumentsString(new AudioCodecArgument(AudioCodec.Aac, AudioQuality.Normal)); - - Assert.IsTrue(str == "-i \"input.mp4\" -codec:a aac -b:a 128k -strict experimental \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -codec:a aac -b:a 128k -strict experimental \"output.mp4\""); } [TestMethod] @@ -66,20 +64,20 @@ public void Builder_BuildString_BitStream() { var str = GetArgumentsString(new BitStreamFilterArgument(Channel.Audio, Filter.H264_Mp4ToAnnexB)); - Assert.IsTrue(str == "-i \"input.mp4\" -bsf:a h264_mp4toannexb \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -bsf:a h264_mp4toannexb \"output.mp4\""); } [TestMethod] public void Builder_BuildString_Concat() { var container = new ArgumentsContainer(); - container.Add(new OutputArgument("output.mp4")); - + container.Add(new ConcatArgument(concatFiles)); + container.Add(new OutputArgument("output.mp4")); var str = builder.BuildArguments(container); - Assert.IsTrue(str == "-i \"concat:1.mp4|2.mp4|3.mp4|4.mp4\" \"output.mp4\""); + Assert.AreEqual(str, "-i \"concat:1.mp4|2.mp4|3.mp4|4.mp4\" \"output.mp4\""); } [TestMethod] @@ -87,7 +85,7 @@ public void Builder_BuildString_Copy_Audio() { var str = GetArgumentsString(new CopyArgument(Channel.Audio)); - Assert.IsTrue(str == "-i \"input.mp4\" -c:a copy \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -c:a copy \"output.mp4\""); } @@ -96,7 +94,7 @@ public void Builder_BuildString_Copy_Video() { var str = GetArgumentsString(new CopyArgument(Channel.Video)); - Assert.IsTrue(str == "-i \"input.mp4\" -c:v copy \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -c:v copy \"output.mp4\""); } [TestMethod] @@ -104,7 +102,7 @@ public void Builder_BuildString_Copy_Both() { var str = GetArgumentsString(new CopyArgument(Channel.Both)); - Assert.IsTrue(str == "-i \"input.mp4\" -c copy \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -c copy \"output.mp4\""); } [TestMethod] @@ -112,7 +110,7 @@ public void Builder_BuildString_CpuSpeed() { var str = GetArgumentsString(new CpuSpeedArgument(10)); - Assert.IsTrue(str == "-i \"input.mp4\" -quality good -cpu-used 10 -deadline realtime \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -quality good -cpu-used 10 -deadline realtime \"output.mp4\""); } [TestMethod] @@ -120,7 +118,7 @@ public void Builder_BuildString_ForceFormat() { var str = GetArgumentsString(new ForceFormatArgument(VideoCodec.LibX264)); - Assert.IsTrue(str == "-i \"input.mp4\" -f libx264 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -f libx264 \"output.mp4\""); } [TestMethod] @@ -128,7 +126,7 @@ public void Builder_BuildString_FrameOutputCount() { var str = GetArgumentsString(new FrameOutputCountArgument(50)); - Assert.IsTrue(str == "-i \"input.mp4\" -vframes 50 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -vframes 50 \"output.mp4\""); } [TestMethod] @@ -136,7 +134,7 @@ public void Builder_BuildString_FrameRate() { var str = GetArgumentsString(new FrameRateArgument(50)); - Assert.IsTrue(str == "-i \"input.mp4\" -r 50 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -r 50 \"output.mp4\""); } [TestMethod] @@ -144,7 +142,7 @@ public void Builder_BuildString_Loop() { var str = GetArgumentsString(new LoopArgument(50)); - Assert.IsTrue(str == "-i \"input.mp4\" -loop 50 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -loop 50 \"output.mp4\""); } [TestMethod] @@ -152,7 +150,7 @@ public void Builder_BuildString_Seek() { var str = GetArgumentsString(new SeekArgument(TimeSpan.FromSeconds(10))); - Assert.IsTrue(str == "-i \"input.mp4\" -ss 00:00:10 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -ss 00:00:10 \"output.mp4\""); } [TestMethod] @@ -160,7 +158,7 @@ public void Builder_BuildString_Shortest() { var str = GetArgumentsString(new ShortestArgument(true)); - Assert.IsTrue(str == "-i \"input.mp4\" -shortest \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -shortest \"output.mp4\""); } [TestMethod] @@ -168,7 +166,7 @@ public void Builder_BuildString_Size() { var str = GetArgumentsString(new SizeArgument(1920, 1080)); - Assert.IsTrue(str == "-i \"input.mp4\" -s 1920x1080 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -s 1920x1080 \"output.mp4\""); } [TestMethod] @@ -176,7 +174,7 @@ public void Builder_BuildString_Speed() { var str = GetArgumentsString(new SpeedArgument(Speed.Fast)); - Assert.IsTrue(str == "-i \"input.mp4\" -preset fast \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -preset fast \"output.mp4\""); } [TestMethod] @@ -184,7 +182,7 @@ public void Builder_BuildString_StartNumber() { var str = GetArgumentsString(new StartNumberArgument(50)); - Assert.IsTrue(str == "-i \"input.mp4\" -start_number 50 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -start_number 50 \"output.mp4\""); } [TestMethod] @@ -192,7 +190,7 @@ public void Builder_BuildString_Threads_1() { var str = GetArgumentsString(new ThreadsArgument(50)); - Assert.IsTrue(str == "-i \"input.mp4\" -threads 50 \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -threads 50 \"output.mp4\""); } [TestMethod] @@ -200,7 +198,7 @@ public void Builder_BuildString_Threads_2() { var str = GetArgumentsString(new ThreadsArgument(true)); - Assert.IsTrue(str == $"-i \"input.mp4\" -threads {Environment.ProcessorCount} \"output.mp4\""); + Assert.AreEqual(str, $"-i \"input.mp4\" -threads {Environment.ProcessorCount} \"output.mp4\""); } @@ -209,7 +207,7 @@ public void Builder_BuildString_Codec() { var str = GetArgumentsString(new VideoCodecArgument(VideoCodec.LibX264)); - Assert.IsTrue(str == "-i \"input.mp4\" -codec:v libx264 -pix_fmt yuv420p \"output.mp4\""); + Assert.AreEqual(str, "-i \"input.mp4\" -codec:v libx264 -pix_fmt yuv420p \"output.mp4\""); } [TestMethod] @@ -217,7 +215,7 @@ public void Builder_BuildString_Codec_Override() { var str = GetArgumentsString(new VideoCodecArgument(VideoCodec.LibX264), new OverrideArgument()); - Assert.IsTrue(str == "-i \"input.mp4\" -codec:v libx264 -pix_fmt yuv420p \"output.mp4\" -y"); + Assert.AreEqual(str, "-i \"input.mp4\" -codec:v libx264 -pix_fmt yuv420p -y \"output.mp4\""); } } } diff --git a/FFMpegCore.Test/VideoTest.cs b/FFMpegCore.Test/VideoTest.cs index 72b27a5..2cb17ee 100644 --- a/FFMpegCore.Test/VideoTest.cs +++ b/FFMpegCore.Test/VideoTest.cs @@ -69,11 +69,17 @@ public void Convert(VideoType type, ArgumentsContainer container) { var input = VideoInfo.FromFileInfo(Input); - container.Add(new InputArgument(input)); - container.Add(new OutputArgument(output)); + var arguments = new ArgumentsContainer(); + arguments.Add(new InputArgument(input)); + foreach (var arg in container) + { + arguments.Add(arg.Value); + } + arguments.Add(new OutputArgument(output)); + var scaling = container.Find(); - Encoder.Convert(container); + Encoder.Convert(arguments); var outputVideo = new VideoInfo(output.FullName); diff --git a/FFMpegCore/FFMPEG/Arguments/DisableChannelArgument.cs b/FFMpegCore/FFMPEG/Arguments/DisableChannelArgument.cs new file mode 100644 index 0000000..3e5778a --- /dev/null +++ b/FFMpegCore/FFMPEG/Arguments/DisableChannelArgument.cs @@ -0,0 +1,27 @@ +using FFMpegCore.FFMPEG.Enums; + +namespace FFMpegCore.FFMPEG.Arguments +{ + /// + /// Represents cpu speed parameter + /// + public class DisableChannelArgument : Argument + { + public DisableChannelArgument() + { + } + + public DisableChannelArgument(Channel value) : base(value) + { + } + + /// + /// String representation of the argument + /// + /// String representation of the argument + public override string GetStringValue() + { + return ArgumentsStringifier.Disable(Value); + } + } +} diff --git a/FFMpegCore/FFMPEG/Arguments/FFArgumentBuilder.cs b/FFMpegCore/FFMPEG/Arguments/FFArgumentBuilder.cs index bc8c81a..8e460d2 100644 --- a/FFMpegCore/FFMPEG/Arguments/FFArgumentBuilder.cs +++ b/FFMpegCore/FFMPEG/Arguments/FFArgumentBuilder.cs @@ -26,68 +26,13 @@ public string BuildArguments(ArgumentsContainer container) CheckContainerException(container); - StringBuilder sb = new StringBuilder(); - sb.Append(GetInput(container).GetStringValue().Trim() + " "); - - foreach(var a in container) - { - if(!IsInputOrOutput(a.Key)) - { - sb.Append(a.Value.GetStringValue().Trim() + " "); - } - } - - sb.Append(container[typeof(OutputArgument)].GetStringValue().Trim()); - - var overrideArg = container.Find(); - if (overrideArg != null) - sb.Append(" " + overrideArg.GetStringValue().Trim()); - - return sb.ToString(); - } - - /// - /// Builds parameters string from that would be passed to ffmpeg process - /// - /// Container of arguments - /// Input file - /// Output file - /// Parameters string - public string BuildArguments(ArgumentsContainer container, FileInfo input, FileInfo output) - { - CheckContainerException(container); - CheckExtensionOfOutputExtension(container, output); - FFMpegHelper.ConversionExceptionCheck(input, output); - - - StringBuilder sb = new StringBuilder(); - - var inputA = new InputArgument(input); - var outputA = new OutputArgument(); - - sb.Append(inputA.GetStringValue().Trim() + " "); - - foreach (var a in container) - { - if (!IsInputOrOutput(a.Key)) - { - sb.Append(a.Value.GetStringValue().Trim() + " "); - } - } - - sb.Append(outputA.GetStringValue().Trim()); - - var overrideArg = container.Find(); - if (overrideArg != null) - sb.Append(" " + overrideArg.GetStringValue().Trim()); - - return sb.ToString(); + return string.Join(" ", container.Select(argument => argument.Value.GetStringValue().Trim())); } private void CheckContainerException(ArgumentsContainer container) { - //TODO: implement arguments check + // TODO: implement arguments check } private void CheckExtensionOfOutputExtension(ArgumentsContainer container, FileInfo output) diff --git a/FFMpegCore/FFMPEG/Arguments/IArgumentBuilder.cs b/FFMpegCore/FFMPEG/Arguments/IArgumentBuilder.cs index 6da8d9f..8bdb681 100644 --- a/FFMpegCore/FFMPEG/Arguments/IArgumentBuilder.cs +++ b/FFMpegCore/FFMPEG/Arguments/IArgumentBuilder.cs @@ -11,7 +11,5 @@ namespace FFMpegCore.FFMPEG.Arguments public interface IArgumentBuilder { string BuildArguments(ArgumentsContainer container); - - string BuildArguments(ArgumentsContainer container, FileInfo input, FileInfo output); } } diff --git a/FFMpegCore/FFMPEG/Arguments/InputArgument.cs b/FFMpegCore/FFMPEG/Arguments/InputArgument.cs index 7d5ac92..5a409df 100644 --- a/FFMpegCore/FFMPEG/Arguments/InputArgument.cs +++ b/FFMpegCore/FFMPEG/Arguments/InputArgument.cs @@ -10,25 +10,25 @@ namespace FFMpegCore.FFMPEG.Arguments /// /// Represents input parameter /// - public class InputArgument : Argument + public class InputArgument : Argument { public InputArgument() { } - public InputArgument(string value) : base(value) + public InputArgument(params string[] values) : base(values) { } - public InputArgument(VideoInfo value) : base(value.FullName) + public InputArgument(params VideoInfo[] values) : base(values.Select(v => v.FullName).ToArray()) { } - public InputArgument(FileInfo value) : base(value.FullName) + public InputArgument(params FileInfo[] values) : base(values.Select(v => v.FullName).ToArray()) { } - public InputArgument(Uri value) : base(value.AbsolutePath) + public InputArgument(params Uri[] values) : base(values.Select(v => v.AbsolutePath).ToArray()) { } @@ -38,7 +38,7 @@ public InputArgument(Uri value) : base(value.AbsolutePath) /// String representation of the argument public override string GetStringValue() { - return ArgumentsStringifier.Input(Value); + return string.Join(" ", Value.Select(v => ArgumentsStringifier.Input(v))); } } } diff --git a/FFMpegCore/FFMPEG/Arguments/OutputArgument.cs b/FFMpegCore/FFMPEG/Arguments/OutputArgument.cs index 35a74df..c3d4872 100644 --- a/FFMpegCore/FFMPEG/Arguments/OutputArgument.cs +++ b/FFMpegCore/FFMPEG/Arguments/OutputArgument.cs @@ -10,7 +10,7 @@ namespace FFMpegCore.FFMPEG.Arguments /// /// Represents output parameter /// - public class OutputArgument : InputArgument + public class OutputArgument : Argument { public OutputArgument() { @@ -20,15 +20,15 @@ public OutputArgument(string value) : base(value) { } - public OutputArgument(VideoInfo value) : base(value) + public OutputArgument(VideoInfo value) : base(value.FullName) { } - public OutputArgument(FileInfo value) : base(value) + public OutputArgument(FileInfo value) : base(value.FullName) { } - public OutputArgument(Uri value) : base(value) + public OutputArgument(Uri value) : base(value.AbsolutePath) { } diff --git a/FFMpegCore/FFMPEG/Arguments/SeekArgument.cs b/FFMpegCore/FFMPEG/Arguments/SeekArgument.cs index e67c934..3110e14 100644 --- a/FFMpegCore/FFMPEG/Arguments/SeekArgument.cs +++ b/FFMpegCore/FFMPEG/Arguments/SeekArgument.cs @@ -9,13 +9,13 @@ namespace FFMpegCore.FFMPEG.Arguments /// /// Represents seek parameter /// - public class SeekArgument : Argument + public class SeekArgument : Argument { public SeekArgument() { } - public SeekArgument(TimeSpan value) : base(value) + public SeekArgument(TimeSpan? value) : base(value) { } diff --git a/FFMpegCore/FFMPEG/Arguments/SizeArgument.cs b/FFMpegCore/FFMPEG/Arguments/SizeArgument.cs index b9eed0c..bbc3a4c 100644 --- a/FFMpegCore/FFMPEG/Arguments/SizeArgument.cs +++ b/FFMpegCore/FFMPEG/Arguments/SizeArgument.cs @@ -17,7 +17,7 @@ public SizeArgument() { } - public SizeArgument(Size value) : base(value) + public SizeArgument(Size? value) : base(value.HasValue ? value.Value : new Size()) { } diff --git a/FFMpegCore/FFMPEG/FFMpeg.cs b/FFMpegCore/FFMPEG/FFMpeg.cs index 6182a86..9d564b8 100644 --- a/FFMpegCore/FFMPEG/FFMpeg.cs +++ b/FFMpegCore/FFMPEG/FFMpeg.cs @@ -91,15 +91,15 @@ public Bitmap Snapshot(VideoInfo source, FileInfo output, Size? size = null, Tim } FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); + var container = new ArgumentsContainer(); + container.Add(new InputArgument(source)); + container.Add(new VideoCodecArgument(VideoCodec.Png)); + container.Add(new FrameOutputCountArgument(1)); + container.Add(new SeekArgument(captureTime)); + container.Add(new SizeArgument(size)); + container.Add(new OutputArgument(output)); - var thumbArgs = ArgumentsStringifier.Input(source) + - ArgumentsStringifier.Video(VideoCodec.Png) + - ArgumentsStringifier.FrameOutputCount(1) + - ArgumentsStringifier.Seek(captureTime) + - ArgumentsStringifier.Size(size) + - ArgumentsStringifier.Output(output); - - if (!RunProcess(thumbArgs, output)) + if (!RunProcess(container, output)) { throw new OperationCanceledException("Could not take snapshot!"); } @@ -150,9 +150,7 @@ public VideoInfo Convert( FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.ForType(type)); FFMpegHelper.ConversionSizeExceptionCheck(source); - string args = ""; - - var scale = VideoSize.Original == size ? 1 : + var scale = VideoSize.Original == size ? 1 : (double)source.Height / (int)size; var outputSize = new Size( @@ -165,38 +163,38 @@ public VideoInfo Convert( outputSize.Width += 1; } + var container = new ArgumentsContainer(); + switch (type) { case VideoType.Mp4: - - args = ArgumentsStringifier.Input(source) + - ArgumentsStringifier.Threads(multithreaded) + - ArgumentsStringifier.Scale(outputSize) + - ArgumentsStringifier.Video(VideoCodec.LibX264, 2400) + - ArgumentsStringifier.Speed(speed) + - ArgumentsStringifier.Audio(AudioCodec.Aac, audioQuality) + - ArgumentsStringifier.Output(output); + container.Add(new InputArgument(source)); + container.Add(new ThreadsArgument(multithreaded)); + container.Add(new ScaleArgument(outputSize)); + container.Add(new VideoCodecArgument(VideoCodec.LibX264, 2400)); + container.Add(new SpeedArgument(speed)); + container.Add(new AudioCodecArgument(AudioCodec.Aac, audioQuality)); + container.Add(new OutputArgument(output)); break; case VideoType.Ogv: - args = ArgumentsStringifier.Input(source) + - ArgumentsStringifier.Threads(multithreaded) + - ArgumentsStringifier.Scale(outputSize) + - ArgumentsStringifier.Video(VideoCodec.LibTheora, 2400) + - ArgumentsStringifier.Speed(16) + - ArgumentsStringifier.Audio(AudioCodec.LibVorbis, audioQuality) + - ArgumentsStringifier.Output(output); - + container.Add(new InputArgument(source)); + container.Add(new ThreadsArgument(multithreaded)); + container.Add(new ScaleArgument(outputSize)); + container.Add(new VideoCodecArgument(VideoCodec.LibTheora, 2400)); + container.Add(new SpeedArgument(speed)); + container.Add(new AudioCodecArgument(AudioCodec.LibVorbis, audioQuality)); + container.Add(new OutputArgument(output)); break; case VideoType.Ts: - args = ArgumentsStringifier.Input(source) + - ArgumentsStringifier.Copy() + - ArgumentsStringifier.BitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB) + - ArgumentsStringifier.ForceFormat(VideoCodec.MpegTs) + - ArgumentsStringifier.Output(output); + container.Add(new InputArgument(source)); + container.Add(new CopyArgument()); + container.Add(new BitStreamFilterArgument(Channel.Video, Filter.H264_Mp4ToAnnexB)); + container.Add(new ForceFormatArgument(VideoCodec.MpegTs)); + container.Add(new OutputArgument(output)); break; } - if (!RunProcess(args, output)) + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Conversion, $"The video could not be converted to {Enum.GetName(typeof(VideoType), type)}"); } @@ -217,15 +215,15 @@ public VideoInfo PosterWithAudio(FileInfo image, FileInfo audio, FileInfo output FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4); FFMpegHelper.ConversionSizeExceptionCheck(Image.FromFile(image.FullName)); - var args = ArgumentsStringifier.Loop(1) + - ArgumentsStringifier.Input(image) + - ArgumentsStringifier.Input(audio) + - ArgumentsStringifier.Video(VideoCodec.LibX264, 2400) + - ArgumentsStringifier.Audio(AudioCodec.Aac, AudioQuality.Normal) + - ArgumentsStringifier.FinalizeAtShortestInput(true) + - ArgumentsStringifier.Output(output); + var container = new ArgumentsContainer(); + container.Add(new LoopArgument(1)); + container.Add(new InputArgument(image.FullName, audio.FullName)); + container.Add(new VideoCodecArgument(VideoCodec.LibX264, 2400)); + container.Add(new AudioCodecArgument(AudioCodec.Aac, AudioQuality.Normal)); + container.Add(new ShortestArgument(true)); + container.Add(new OutputArgument(output)); - if (!RunProcess(args, output)) + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "An error occured while adding the audio file to the image."); } @@ -256,14 +254,15 @@ public VideoInfo Join(FileInfo output, params VideoInfo[] videos) return destinationPath; }).ToList(); - var args = ArgumentsStringifier.InputConcat(temporaryVideoParts) + - ArgumentsStringifier.Copy() + - ArgumentsStringifier.BitStreamFilter(Channel.Audio, Filter.Aac_AdtstoAsc) + - ArgumentsStringifier.Output(output); + var container = new ArgumentsContainer(); + container.Add(new ConcatArgument(temporaryVideoParts)); + container.Add(new CopyArgument()); + container.Add(new BitStreamFilterArgument(Channel.Audio, Filter.Aac_AdtstoAsc)); + container.Add(new OutputArgument(output)); try { - if (!RunProcess(args, output)) + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not join the provided video files."); } @@ -284,7 +283,7 @@ public VideoInfo Join(FileInfo output, params VideoInfo[] videos) /// Image sequence collection /// Output video information. public VideoInfo JoinImageSequence(FileInfo output, double frameRate = 30, params ImageInfo[] images) - { + { var temporaryImageFiles = images.Select((image, index) => { FFMpegHelper.ConversionSizeExceptionCheck(Image.FromFile(image.FullName)); @@ -296,17 +295,18 @@ public VideoInfo JoinImageSequence(FileInfo output, double frameRate = 30, param var firstImage = images.First(); - var args = ArgumentsStringifier.FrameRate(frameRate) + - ArgumentsStringifier.Size(new Size(firstImage.Width, firstImage.Height)) + - ArgumentsStringifier.StartNumber(0) + - ArgumentsStringifier.Input($"{firstImage.Directory}\\%09d.png") + - ArgumentsStringifier.FrameOutputCount(images.Length) + - ArgumentsStringifier.Video(VideoCodec.LibX264) + - ArgumentsStringifier.Output(output); + var container = new ArgumentsContainer(); + container.Add(new FrameRateArgument(frameRate)); + container.Add(new SizeArgument(firstImage.Width, firstImage.Height)); + container.Add(new StartNumberArgument(0)); + container.Add(new InputArgument($"{firstImage.Directory}\\%09d.png")); + container.Add(new FrameOutputCountArgument(images.Length)); + container.Add(new VideoCodecArgument(VideoCodec.LibX264)); + container.Add(new OutputArgument(output)); try { - if (!RunProcess(args, output)) + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not join the provided image sequence."); } @@ -331,10 +331,11 @@ public VideoInfo SaveM3U8Stream(Uri uri, FileInfo output) if (uri.Scheme == "http" || uri.Scheme == "https") { - var args = ArgumentsStringifier.Input(uri) + - ArgumentsStringifier.Output(output); - - if (!RunProcess(args, output)) + var container = new ArgumentsContainer(); + container.Add(new InputArgument(uri)); + container.Add(new OutputArgument(output)); + + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, $"Saving the ${uri.AbsoluteUri} stream failed."); } @@ -356,12 +357,13 @@ public VideoInfo Mute(VideoInfo source, FileInfo output) FFMpegHelper.ConversionSizeExceptionCheck(source); FFMpegHelper.ExtensionExceptionCheck(output, source.Extension); - var args = ArgumentsStringifier.Input(source) + - ArgumentsStringifier.Copy() + - ArgumentsStringifier.Disable(Channel.Audio) + - ArgumentsStringifier.Output(output); + var container = new ArgumentsContainer(); + container.Add(new InputArgument(source)); + container.Add(new CopyArgument()); + container.Add(new DisableChannelArgument(Channel.Audio)); + container.Add(new OutputArgument(output)); - if (!RunProcess(args, output)) + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not mute the requested video."); } @@ -380,11 +382,12 @@ public FileInfo ExtractAudio(VideoInfo source, FileInfo output) FFMpegHelper.ConversionExceptionCheck(source.ToFileInfo(), output); FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp3); - var args = ArgumentsStringifier.Input(source) + - ArgumentsStringifier.Disable(Channel.Video) + - ArgumentsStringifier.Output(output); + var container = new ArgumentsContainer(); + container.Add(new InputArgument(source)); + container.Add(new DisableChannelArgument(Channel.Video)); + container.Add(new OutputArgument(output)); - if (!RunProcess(args, output)) + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not extract the audio from the requested video."); } @@ -409,14 +412,15 @@ public VideoInfo ReplaceAudio(VideoInfo source, FileInfo audio, FileInfo output, FFMpegHelper.ConversionSizeExceptionCheck(source); FFMpegHelper.ExtensionExceptionCheck(output, source.Extension); - var args = ArgumentsStringifier.Input(source) + - ArgumentsStringifier.Input(audio) + - ArgumentsStringifier.Copy(Channel.Video) + - ArgumentsStringifier.Audio(AudioCodec.Aac, AudioQuality.Hd) + - ArgumentsStringifier.FinalizeAtShortestInput(stopAtShortest) + - ArgumentsStringifier.Output(output); + var container = new ArgumentsContainer(); + container.Add(new InputArgument(source.FullName, audio.FullName)); + //container.Add(new InputArgument(audio)); + container.Add(new CopyArgument()); + container.Add(new AudioCodecArgument(AudioCodec.Aac, AudioQuality.Hd)); + container.Add(new ShortestArgument(stopAtShortest)); + container.Add(new OutputArgument(output)); - if (!RunProcess(args, output)) + if (!RunProcess(container, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not replace the video audio."); } @@ -429,19 +433,7 @@ public VideoInfo Convert(ArgumentsContainer arguments) var args = argumentBuilder.BuildArguments(arguments); var output = ((OutputArgument)arguments[typeof(OutputArgument)]).GetAsFileInfo(); - if (!RunProcess(args, output)) - { - throw new FFMpegException(FFMpegExceptionType.Operation, "Could not replace the video audio."); - } - - return new VideoInfo(output); - } - - public VideoInfo Convert(ArgumentsContainer arguments, FileInfo input, FileInfo output) - { - var args = argumentBuilder.BuildArguments(arguments, input, output); - - if (!RunProcess(args, output)) + if (!RunProcess(arguments, output)) { throw new FFMpegException(FFMpegExceptionType.Operation, "Could not replace the video audio."); } @@ -467,11 +459,11 @@ public void Stop() private volatile StringBuilder _errorOutput = new StringBuilder(); - private bool RunProcess(string args, FileInfo output) + private bool RunProcess(ArgumentsContainer container, FileInfo output) { var successState = true; - CreateProcess(args, _ffmpegPath, true, rStandardError: true); + CreateProcess(this.argumentBuilder.BuildArguments(container), _ffmpegPath, true, rStandardError: true); try {