using FFMpegCore.Enums; using FFMpegCore.Exceptions; using FFMpegCore.Extend; using FFMpegCore.Pipes; using FFMpegCore.Test.Resources; namespace FFMpegCore.Test; [TestClass] public class AudioTest { public TestContext TestContext { get; set; } [TestMethod] public void Audio_Remove() { using var outputFile = new TemporaryFile("out.mp4"); FFMpeg.Mute(TestResources.Mp4Video, outputFile); var analysis = FFProbe.Analyse(outputFile); Assert.IsNotEmpty(analysis.VideoStreams); Assert.IsEmpty(analysis.AudioStreams); } [TestMethod] public void Audio_Save() { using var outputFile = new TemporaryFile("out.mp3"); FFMpeg.ExtractAudio(TestResources.Mp4Video, outputFile); var analysis = FFProbe.Analyse(outputFile); Assert.IsNotEmpty(analysis.AudioStreams); Assert.IsEmpty(analysis.VideoStreams); } [TestMethod] public async Task Audio_FromRaw() { await using var file = File.Open(TestResources.RawAudio, FileMode.Open); var memoryStream = new MemoryStream(); await FFMpegArguments .FromPipeInput(new StreamPipeSource(file), options => options.ForceFormat("s16le")) .OutputToPipe(new StreamPipeSink(memoryStream), options => options.ForceFormat("mp3")) .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); } [TestMethod] public void Audio_Add() { using var outputFile = new TemporaryFile("out.mp4"); var success = FFMpeg.ReplaceAudio(TestResources.Mp4WithoutAudio, TestResources.Mp3Audio, outputFile); var videoAnalysis = FFProbe.Analyse(TestResources.Mp4WithoutAudio); var audioAnalysis = FFProbe.Analyse(TestResources.Mp3Audio); var outputAnalysis = FFProbe.Analyse(outputFile); Assert.IsTrue(success); Assert.AreEqual(Math.Max(videoAnalysis.Duration.TotalSeconds, audioAnalysis.Duration.TotalSeconds), outputAnalysis.Duration.TotalSeconds, 0.15); Assert.IsTrue(File.Exists(outputFile)); } [TestMethod] public void Image_AddAudio() { using var outputFile = new TemporaryFile("out.mp4"); FFMpeg.PosterWithAudio(TestResources.PngImage, TestResources.Mp3Audio, outputFile); var analysis = FFProbe.Analyse(TestResources.Mp3Audio); Assert.IsGreaterThan(0, analysis.Duration.TotalSeconds); Assert.IsTrue(File.Exists(outputFile)); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var samples = new List { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) }; var audioSamplesSource = new RawAudioPipeSource(samples) { Channels = 2, Format = "s8", SampleRate = 8000 }; var success = FFMpegArguments .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_ToLibVorbis_Args_Pipe() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var samples = new List { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) }; var audioSamplesSource = new RawAudioPipeSource(samples) { Channels = 2, Format = "s8", SampleRate = 8000 }; var success = FFMpegArguments .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.LibVorbis)) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public async Task Audio_ToAAC_Args_Pipe_Async() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var samples = new List { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) }; var audioSamplesSource = new RawAudioPipeSource(samples) { Channels = 2, Format = "s8", SampleRate = 8000 }; var success = await FFMpegArguments .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) .CancellableThrough(TestContext.CancellationToken) .ProcessAsynchronously(); Assert.IsTrue(success); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_ValidDefaultConfiguration() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var samples = new List { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) }; var audioSamplesSource = new RawAudioPipeSource(samples); var success = FFMpegArguments .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_InvalidChannels() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var audioSamplesSource = new RawAudioPipeSource(new List()) { Channels = 0 }; Assert.ThrowsExactly(() => FFMpegArguments .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_InvalidFormat() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var audioSamplesSource = new RawAudioPipeSource(new List()) { Format = "s8le" }; Assert.ThrowsExactly(() => FFMpegArguments .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_ToAAC_Args_Pipe_InvalidSampleRate() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var audioSamplesSource = new RawAudioPipeSource(new List()) { SampleRate = 0 }; Assert.ThrowsExactly(() => FFMpegArguments .FromPipeInput(audioSamplesSource) .OutputToFile(outputFile, false, opt => opt .WithAudioCodec(AudioCodec.Aac)) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_Pan_ToMono() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var success = FFMpegArguments.FromFileInput(TestResources.Mp3Audio) .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan(1, "c0 < 0.9 * c0 + 0.1 * c1"))) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); var mediaAnalysis = FFProbe.Analyse(outputFile); Assert.IsTrue(success); Assert.HasCount(1, mediaAnalysis.AudioStreams); Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_Pan_ToMonoNoDefinitions() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); var success = FFMpegArguments.FromFileInput(TestResources.Mp3Audio) .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan(1))) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); var mediaAnalysis = FFProbe.Analyse(outputFile); Assert.IsTrue(success); Assert.HasCount(1, mediaAnalysis.AudioStreams); Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_Pan_ToMonoChannelsToOutputDefinitionsMismatch() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); Assert.ThrowsExactly(() => FFMpegArguments.FromFileInput(TestResources.Mp3Audio) .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan(1, "c0=c0", "c1=c1"))) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] public void Audio_Pan_ToMonoChannelsLayoutToOutputDefinitionsMismatch() { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); Assert.ThrowsExactly(() => FFMpegArguments.FromFileInput(TestResources.Mp3Audio) .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.Pan("mono", "c0=c0", "c1=c1"))) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] 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())) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] 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))) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously(); Assert.IsTrue(success); } [TestMethod] [Timeout(10000, CooperativeCancellation = true)] [DataRow(2)] [DataRow(32)] [DataRow(8)] public void Audio_DynamicNormalizer_FilterWindow(int filterWindow) { using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}"); Assert.ThrowsExactly(() => FFMpegArguments .FromFileInput(TestResources.Mp3Audio) .OutputToFile(outputFile, true, argumentOptions => argumentOptions .WithAudioFilters(filter => filter.DynamicNormalizer(filterWindow: filterWindow))) .CancellableThrough(TestContext.CancellationToken) .ProcessSynchronously()); } }