diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs index cde8da2..08be2f8 100644 --- a/FFMpegCore.Test/ArgumentBuilderTest.cs +++ b/FFMpegCore.Test/ArgumentBuilderTest.cs @@ -9,10 +9,10 @@ namespace FFMpegCore.Test [TestClass] public class ArgumentBuilderTest : BaseTest { - List concatFiles = new List + private List concatFiles = new List { "1.mp4", "2.mp4", "3.mp4", "4.mp4"}; - FFArgumentBuilder builder; + private FFArgumentBuilder builder; public ArgumentBuilderTest() : base() { @@ -21,7 +21,7 @@ public ArgumentBuilderTest() : base() private string GetArgumentsString(params Argument[] args) { - var container = new ArgumentContainer {new InputArgument("input.mp4")}; + var container = new ArgumentContainer { new InputArgument("input.mp4") }; foreach (var a in args) { container.Add(a); @@ -31,7 +31,6 @@ private string GetArgumentsString(params Argument[] args) return builder.BuildArguments(container); } - [TestMethod] public void Builder_BuildString_IO_1() { @@ -51,8 +50,22 @@ public void Builder_BuildString_Scale() [TestMethod] public void Builder_BuildString_AudioCodec() { - var str = GetArgumentsString(new AudioCodecArgument(AudioCodec.Aac, AudioQuality.Normal)); - Assert.AreEqual(str, "-i \"input.mp4\" -c:a aac -b:a 128k \"output.mp4\""); + var str = GetArgumentsString(new AudioCodecArgument(AudioCodec.Aac)); + Assert.AreEqual(str, "-i \"input.mp4\" -c:a aac \"output.mp4\""); + } + + [TestMethod] + public void Builder_BuildString_AudioBitrate() + { + var str = GetArgumentsString(new AudioBitrateArgument(AudioQuality.Normal)); + Assert.AreEqual(str, "-i \"input.mp4\" -b:a 128k \"output.mp4\""); + } + + [TestMethod] + public void Builder_BuildString_Quiet() + { + var str = GetArgumentsString(new QuietArgument()); + Assert.AreEqual(str, "-i \"input.mp4\" -hide_banner -loglevel warning \"output.mp4\""); } [TestMethod] @@ -66,8 +79,7 @@ public void Builder_BuildString_BitStream() [TestMethod] public void Builder_BuildString_Concat() { - var container = new ArgumentContainer {new ConcatArgument(concatFiles), new OutputArgument("output.mp4")}; - + var container = new ArgumentContainer { new ConcatArgument(concatFiles), new OutputArgument("output.mp4") }; var str = builder.BuildArguments(container); @@ -82,7 +94,6 @@ public void Builder_BuildString_Copy_Audio() Assert.AreEqual(str, "-i \"input.mp4\" -c:a copy \"output.mp4\""); } - [TestMethod] public void Builder_BuildString_Copy_Video() { @@ -174,7 +185,7 @@ public void Builder_BuildString_Speed() [TestMethod] public void Builder_BuildString_DrawtextFilter() { - var str = GetArgumentsString(new DrawTextArgument("Stack Overflow", "/path/to/font.ttf", + var str = GetArgumentsString(new DrawTextArgument("Stack Overflow", "/path/to/font.ttf", ("fontcolor", "white"), ("fontsize", "24"), ("box", "1"), @@ -198,7 +209,7 @@ public void Builder_BuildString_StartNumber() public void Builder_BuildString_Threads_1() { var str = GetArgumentsString(new ThreadsArgument(50)); - + Assert.AreEqual(str, "-i \"input.mp4\" -threads 50 \"output.mp4\""); } @@ -210,7 +221,6 @@ public void Builder_BuildString_Threads_2() Assert.AreEqual(str, $"-i \"input.mp4\" -threads {Environment.ProcessorCount} \"output.mp4\""); } - [TestMethod] public void Builder_BuildString_Codec() { @@ -228,10 +238,21 @@ public void Builder_BuildString_Codec_Override() } [TestMethod] - public void Builder_BuildString_Duration() { + public void Builder_BuildString_Duration() + { var str = GetArgumentsString(new DurationArgument(TimeSpan.FromSeconds(20))); Assert.AreEqual(str, "-i \"input.mp4\" -t 00:00:20 \"output.mp4\""); } + + [TestMethod] + public void Builder_BuildString_Raw() + { + var str = GetArgumentsString(new CustomArgument(null)); + Assert.AreEqual(str, "-i \"input.mp4\" \"output.mp4\""); + + str = GetArgumentsString(new CustomArgument("-acodec copy")); + Assert.AreEqual(str, "-i \"input.mp4\" -acodec copy \"output.mp4\""); + } } -} +} \ No newline at end of file diff --git a/FFMpegCore/FFMPEG/Argument/Atoms/AudioBitrateArgument.cs b/FFMpegCore/FFMPEG/Argument/Atoms/AudioBitrateArgument.cs new file mode 100644 index 0000000..7ecde09 --- /dev/null +++ b/FFMpegCore/FFMPEG/Argument/Atoms/AudioBitrateArgument.cs @@ -0,0 +1,19 @@ +using FFMpegCore.FFMPEG.Enums; + +namespace FFMpegCore.FFMPEG.Argument +{ + /// + /// Represents parameter of audio codec and it's quality + /// + public class AudioBitrateArgument : Argument + { + public AudioBitrateArgument(AudioQuality value) : base((int)value) { } + public AudioBitrateArgument(int bitrate) : base(bitrate) { } + + /// + public override string GetStringValue() + { + return $"-b:a {Value}k"; + } + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMPEG/Argument/Atoms/AudioCodecArgument.cs b/FFMpegCore/FFMPEG/Argument/Atoms/AudioCodecArgument.cs index 7cdb6c5..9c75386 100644 --- a/FFMpegCore/FFMPEG/Argument/Atoms/AudioCodecArgument.cs +++ b/FFMpegCore/FFMPEG/Argument/Atoms/AudioCodecArgument.cs @@ -7,26 +7,12 @@ namespace FFMpegCore.FFMPEG.Argument /// public class AudioCodecArgument : Argument { - /// - /// Bitrate of audio channel - /// - public int Bitrate { get; } = (int)AudioQuality.Normal; - - public AudioCodecArgument() { } - public AudioCodecArgument(AudioCodec value) : base(value) { } - public AudioCodecArgument(AudioCodec value, AudioQuality bitrate) : this(value, (int) bitrate) { } - - public AudioCodecArgument(AudioCodec value, int bitrate) : base(value) - { - Bitrate = bitrate; - } - /// public override string GetStringValue() { - return $"-c:a {Value.ToString().ToLower()} -b:a {Bitrate}k"; + return $"-c:a {Value.ToString().ToLower()}"; } } } diff --git a/FFMpegCore/FFMPEG/Argument/Atoms/CustomArgument.cs b/FFMpegCore/FFMPEG/Argument/Atoms/CustomArgument.cs new file mode 100644 index 0000000..6a38b4e --- /dev/null +++ b/FFMpegCore/FFMPEG/Argument/Atoms/CustomArgument.cs @@ -0,0 +1,14 @@ +namespace FFMpegCore.FFMPEG.Argument +{ + public class CustomArgument : Argument + { + public CustomArgument(string argument) : base(argument) + { + } + + public override string GetStringValue() + { + return Value ?? string.Empty; + } + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMPEG/Argument/Atoms/QuietArgument.cs b/FFMpegCore/FFMPEG/Argument/Atoms/QuietArgument.cs new file mode 100644 index 0000000..a5d5c2e --- /dev/null +++ b/FFMpegCore/FFMPEG/Argument/Atoms/QuietArgument.cs @@ -0,0 +1,10 @@ +namespace FFMpegCore.FFMPEG.Argument +{ + public class QuietArgument : Argument + { + public override string GetStringValue() + { + return "-hide_banner -loglevel warning"; + } + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMPEG/FFMpeg.cs b/FFMpegCore/FFMPEG/FFMpeg.cs index b99e564..79929bf 100644 --- a/FFMpegCore/FFMPEG/FFMpeg.cs +++ b/FFMpegCore/FFMPEG/FFMpeg.cs @@ -151,7 +151,8 @@ public VideoInfo Convert( new ScaleArgument(outputSize), new VideoCodecArgument(VideoCodec.LibX264, 2400), new SpeedArgument(speed), - new AudioCodecArgument(AudioCodec.Aac, audioQuality), + new AudioCodecArgument(AudioCodec.Aac), + new AudioBitrateArgument(audioQuality), new OutputArgument(output))), VideoType.Ogv => Convert(new ArgumentContainer( new InputArgument(source), @@ -159,7 +160,8 @@ public VideoInfo Convert( new ScaleArgument(outputSize), new VideoCodecArgument(VideoCodec.LibTheora, 2400), new SpeedArgument(speed), - new AudioCodecArgument(AudioCodec.LibVorbis, audioQuality), + new AudioCodecArgument(AudioCodec.LibVorbis), + new AudioBitrateArgument(audioQuality), new OutputArgument(output))), VideoType.Ts => Convert(new ArgumentContainer( new InputArgument(source), @@ -173,7 +175,8 @@ public VideoInfo Convert( new ScaleArgument(outputSize), new VideoCodecArgument(VideoCodec.LibVpx, 2400), new SpeedArgument(speed), - new AudioCodecArgument(AudioCodec.LibVorbis, audioQuality), + new AudioCodecArgument(AudioCodec.LibVorbis), + new AudioBitrateArgument(audioQuality), new OutputArgument(output))), _ => throw new ArgumentOutOfRangeException(nameof(type)) }; @@ -196,7 +199,8 @@ public VideoInfo PosterWithAudio(FileInfo image, FileInfo audio, FileInfo output new InputArgument(image.FullName, audio.FullName), new LoopArgument(1), new VideoCodecArgument(VideoCodec.LibX264, 2400), - new AudioCodecArgument(AudioCodec.Aac, AudioQuality.Normal), + new AudioCodecArgument(AudioCodec.Aac), + new AudioBitrateArgument(AudioQuality.Normal), new ShortestArgument(true), new OutputArgument(output) ); @@ -377,7 +381,8 @@ public VideoInfo ReplaceAudio(VideoInfo source, FileInfo audio, FileInfo output, return Convert(new ArgumentContainer( new InputArgument(source.FullName, audio.FullName), new CopyArgument(), - new AudioCodecArgument(AudioCodec.Aac, AudioQuality.Hd), + new AudioCodecArgument(AudioCodec.Aac), + new AudioBitrateArgument(AudioQuality.Hd), new ShortestArgument(stopAtShortest), new OutputArgument(output) )); @@ -394,9 +399,7 @@ public VideoInfo Convert(ArgumentContainer arguments, bool skipExistsCheck = fal _totalTime = TimeSpan.MinValue; - if (output == null) - return null; - return new VideoInfo(output); + return output != null && output.Exists ? new VideoInfo(output) : null; } public async Task ConvertAsync(ArgumentContainer arguments, bool skipExistsCheck = false) { @@ -408,9 +411,8 @@ public async Task ConvertAsync(ArgumentContainer arguments, bool skip throw new FFMpegException(FFMpegExceptionType.Conversion, "Could not process file without error"); _totalTime = TimeSpan.MinValue; - if (output == null) - return null; - return new VideoInfo(output); + + return output != null && output.Exists ? new VideoInfo(output) : null; } private static (VideoInfo[] Input, FileInfo Output) GetInputOutput(ArgumentContainer arguments) diff --git a/FFMpegCore/FFMPEG/FFProbe.cs b/FFMpegCore/FFMPEG/FFProbe.cs index 3030344..d73a8f5 100644 --- a/FFMpegCore/FFMPEG/FFProbe.cs +++ b/FFMpegCore/FFMPEG/FFProbe.cs @@ -147,7 +147,7 @@ private VideoInfo ParseVideoInfoInternal(VideoInfo info, string probeOutput) { var metadata = JsonConvert.DeserializeObject(probeOutput); - if (metadata.Streams == null || metadata.Streams.Count == 0) + if (metadata?.Streams == null || metadata.Streams.Count == 0) { throw new FFMpegException(FFMpegExceptionType.File, $"No video or audio streams could be detected. Source: ${info.FullName}"); } diff --git a/README.md b/README.md index d5d7462..b58aa79 100644 --- a/README.md +++ b/README.md @@ -358,9 +358,9 @@ public enum VideoCodec } ``` ### ArgumentBuilder -Custom video converting presets could be created with help of `ArgumentsContainer` class: +Custom video converting presets could be created with help of `ArgumentContainer` class: ```csharp -var container = new ArgumentsContainer(); +var container = new ArgumentContainer(); container.Add(new VideoCodecArgument(VideoCodec.LibX264)); container.Add(new ScaleArgument(VideoSize.Hd)); @@ -368,7 +368,7 @@ var ffmpeg = new FFMpeg(); var result = ffmpeg.Convert(container, new FileInfo("input.mp4"), new FileInfo("output.mp4")); ``` -Other availible arguments could be found in `FFMpegCore.FFMPEG.Arguments` namespace. +Other availible arguments could be found in `FFMpegCore.FFMPEG.Argument` namespace. If you need to create your custom argument, you just need to create new class, that is inherited from `Argument`, `Argument` or `Argument` For example: