mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
parent
d7be7aa5ac
commit
152648275f
4 changed files with 124 additions and 1 deletions
|
@ -447,5 +447,27 @@ public void Builder_BuildString_PanAudioFilterChannelNoOutputDefinition()
|
||||||
|
|
||||||
Assert.AreEqual("-i \"input.mp4\" -af \"pan=stereo\" \"output.mp4\"", str);
|
Assert.AreEqual("-i \"input.mp4\" -af \"pan=stereo\" \"output.mp4\"", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Builder_BuildString_DynamicAudioNormalizerDefaultFormat()
|
||||||
|
{
|
||||||
|
var str = FFMpegArguments.FromFileInput("input.mp4")
|
||||||
|
.OutputToFile("output.mp4", false,
|
||||||
|
opt => opt.WithAudioFilters(filterOptions => filterOptions.DynamicNormalizer()))
|
||||||
|
.Arguments;
|
||||||
|
|
||||||
|
Assert.AreEqual("-i \"input.mp4\" -af \"dynaudnorm=f=500:g=31:p=0.95:m=10.0:r=0.0:n=1:c=0:b=0:s=0.0\" \"output.mp4\"", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void Builder_BuildString_DynamicAudioNormalizerWithValuesFormat()
|
||||||
|
{
|
||||||
|
var str = FFMpegArguments.FromFileInput("input.mp4")
|
||||||
|
.OutputToFile("output.mp4", false,
|
||||||
|
opt => opt.WithAudioFilters(filterOptions => filterOptions.DynamicNormalizer(125, 13, 0.9215, 5.124, 0.5458,false,true,true, 0.3333333)))
|
||||||
|
.Arguments;
|
||||||
|
|
||||||
|
Assert.AreEqual("-i \"input.mp4\" -af \"dynaudnorm=f=125:g=13:p=0.92:m=5.1:r=0.5:n=0:c=1:b=1:s=0.3\" \"output.mp4\"", str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
using FFMpegCore.Extend;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
using FFMpegCore.Test.Resources;
|
using FFMpegCore.Test.Resources;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
@ -8,7 +9,6 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FFMpegCore.Extend;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
|
@ -281,5 +281,51 @@ public void Audio_Pan_ToMonoChannelsLayoutToOutputDefinitionsMismatch()
|
||||||
.WithAudioFilters(filter => filter.Pan("mono", "c0=c0", "c1=c1")))
|
.WithAudioFilters(filter => filter.Pan("mono", "c0=c0", "c1=c1")))
|
||||||
.ProcessSynchronously());
|
.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_DynamicNormalizer_WithDefaultValues()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var success = FFMpegArguments.FromFileInput(TestResources.Mp3Audio)
|
||||||
|
.OutputToFile(outputFile, true,
|
||||||
|
argumentOptions => argumentOptions
|
||||||
|
.WithAudioFilters(filter => filter.DynamicNormalizer()))
|
||||||
|
.ProcessSynchronously();
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod, Timeout(10000)]
|
||||||
|
public void Audio_DynamicNormalizer_WithNonDefaultValues()
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var success = FFMpegArguments.FromFileInput(TestResources.Mp3Audio)
|
||||||
|
.OutputToFile(outputFile, true,
|
||||||
|
argumentOptions => argumentOptions
|
||||||
|
.WithAudioFilters(
|
||||||
|
filter => filter.DynamicNormalizer(250, 7, 0.9, 2, 1, false, true, true, 0.5)))
|
||||||
|
.ProcessSynchronously();
|
||||||
|
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataTestMethod, Timeout(10000)]
|
||||||
|
[DataRow(2)]
|
||||||
|
[DataRow(32)]
|
||||||
|
[DataRow(8)]
|
||||||
|
public void Audio_DynamicNormalizer_FilterWindow(int filterWindow)
|
||||||
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
|
var ex = Assert.ThrowsException<ArgumentOutOfRangeException>(() => FFMpegArguments
|
||||||
|
.FromFileInput(TestResources.Mp3Audio)
|
||||||
|
.OutputToFile(outputFile, true,
|
||||||
|
argumentOptions => argumentOptions
|
||||||
|
.WithAudioFilters(
|
||||||
|
filter => filter.DynamicNormalizer(filterWindow: filterWindow)))
|
||||||
|
.ProcessSynchronously());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -44,6 +44,12 @@ public class AudioFilterOptions
|
||||||
|
|
||||||
public AudioFilterOptions Pan(string channelLayout, params string[] outputDefinitions) => WithArgument(new PanArgument(channelLayout, outputDefinitions));
|
public AudioFilterOptions Pan(string channelLayout, params string[] outputDefinitions) => WithArgument(new PanArgument(channelLayout, outputDefinitions));
|
||||||
public AudioFilterOptions Pan(int channels, params string[] outputDefinitions) => WithArgument(new PanArgument(channels, outputDefinitions));
|
public AudioFilterOptions Pan(int channels, params string[] outputDefinitions) => WithArgument(new PanArgument(channels, outputDefinitions));
|
||||||
|
public AudioFilterOptions DynamicNormalizer(int frameLength = 500, int filterWindow = 31, double targetPeak = 0.95,
|
||||||
|
double gainFactor = 10.0, double targetRms = 0.0, bool channelCoupling = true,
|
||||||
|
bool enableDcBiasCorrection = false, bool enableAlternativeBoundary = false,
|
||||||
|
double compressorFactor = 0.0) => WithArgument(new DynamicNormalizerArgument(frameLength, filterWindow,
|
||||||
|
targetPeak, gainFactor, targetRms, channelCoupling, enableDcBiasCorrection, enableAlternativeBoundary,
|
||||||
|
compressorFactor));
|
||||||
|
|
||||||
private AudioFilterOptions WithArgument(IAudioFilterArgument argument)
|
private AudioFilterOptions WithArgument(IAudioFilterArgument argument)
|
||||||
{
|
{
|
||||||
|
|
49
FFMpegCore/FFMpeg/Arguments/DynamicNormalizerArgument.cs
Normal file
49
FFMpegCore/FFMpeg/Arguments/DynamicNormalizerArgument.cs
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace FFMpegCore.Arguments
|
||||||
|
{
|
||||||
|
public class DynamicNormalizerArgument : IAudioFilterArgument
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, string> _arguments = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dynamic Audio Normalizer. <see href="https://ffmpeg.org/ffmpeg-filters.html#dynaudnorm"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="frameLength">Set the frame length in milliseconds. Must be between 10 to 8000. The default value is 500</param>
|
||||||
|
/// <param name="filterWindow">Set the Gaussian filter window size. In range from 3 to 301, must be odd number. The default value is 31</param>
|
||||||
|
/// <param name="targetPeak">Set the target peak value. The default value is 0.95</param>
|
||||||
|
/// <param name="gainFactor">Set the maximum gain factor. In range from 1.0 to 100.0. Default is 10.0.</param>
|
||||||
|
/// <param name="targetRms">Set the target RMS. In range from 0.0 to 1.0. Default to 0.0 (disabled)</param>
|
||||||
|
/// <param name="channelCoupling">Enable channels coupling. By default is enabled.</param>
|
||||||
|
/// <param name="enableDcBiasCorrection">Enable DC bias correction. By default is disabled.</param>
|
||||||
|
/// <param name="enableAlternativeBoundary">Enable alternative boundary mode. By default is disabled.</param>
|
||||||
|
/// <param name="compressorFactor">Set the compress factor. In range from 0.0 to 30.0. Default is 0.0 (disabled).</param>
|
||||||
|
public DynamicNormalizerArgument(int frameLength = 500, int filterWindow = 31, double targetPeak = 0.95, double gainFactor = 10.0, double targetRms = 0.0, bool channelCoupling = true, bool enableDcBiasCorrection = false, bool enableAlternativeBoundary = false, double compressorFactor = 0.0)
|
||||||
|
{
|
||||||
|
if (frameLength < 10 || frameLength > 8000) throw new ArgumentOutOfRangeException(nameof(frameLength),"Frame length must be between 10 to 8000");
|
||||||
|
if (filterWindow < 3 || filterWindow > 31) throw new ArgumentOutOfRangeException(nameof(filterWindow), "Gaussian filter window size must be between 3 to 31");
|
||||||
|
if (filterWindow % 2 == 0) throw new ArgumentOutOfRangeException(nameof(filterWindow), "Gaussian filter window size must be an odd number");
|
||||||
|
if (targetPeak <= 0 || targetPeak > 1) throw new ArgumentOutOfRangeException(nameof(targetPeak));
|
||||||
|
if (gainFactor < 1 || gainFactor > 100) throw new ArgumentOutOfRangeException(nameof(gainFactor), "Gain factor must be between 1.0 to 100.0");
|
||||||
|
if (targetRms < 0 || targetRms > 1) throw new ArgumentOutOfRangeException(nameof(targetRms), "Target RMS must be between 0.0 and 1.0");
|
||||||
|
if (compressorFactor < 0 || compressorFactor > 30) throw new ArgumentOutOfRangeException(nameof(compressorFactor), "Compressor factor must be between 0.0 and 30.0");
|
||||||
|
|
||||||
|
_arguments.Add("f", frameLength.ToString());
|
||||||
|
_arguments.Add("g", filterWindow.ToString());
|
||||||
|
_arguments.Add("p", targetPeak.ToString("0.00", CultureInfo.InvariantCulture));
|
||||||
|
_arguments.Add("m", gainFactor.ToString("0.0", CultureInfo.InvariantCulture));
|
||||||
|
_arguments.Add("r", targetRms.ToString("0.0", CultureInfo.InvariantCulture));
|
||||||
|
_arguments.Add("n", (channelCoupling ? 1 : 0).ToString());
|
||||||
|
_arguments.Add("c", (enableDcBiasCorrection ? 1 : 0).ToString());
|
||||||
|
_arguments.Add("b", (enableAlternativeBoundary ? 1 : 0).ToString());
|
||||||
|
_arguments.Add("s", compressorFactor.ToString("0.0", CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Key { get; } = "dynaudnorm";
|
||||||
|
|
||||||
|
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue