This commit is contained in:
Adrianus Molendijk 2024-03-04 00:56:14 +00:00 committed by GitHub
commit f38fde0c61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 134 additions and 1 deletions

View file

@ -9,6 +9,7 @@ namespace FFMpegCore.Test
public class ArgumentBuilderTest
{
private readonly string[] _concatFiles = { "1.mp4", "2.mp4", "3.mp4", "4.mp4" };
private readonly string[] _multiFiles = { "1.mp3", "2.mp3", "3.mp3", "4.mp3" };
[TestMethod]
public void Builder_BuildString_IO_1()
@ -611,5 +612,86 @@ public void Builder_BuildString_TeeOutput()
-i "input.mp4" -f tee "[movflags=faststart]output.mp4|[f=mpegts:select=\'0:v:0\']http://server/path"
""", str);
}
[TestMethod]
public void Builder_BuildString_MultiInput()
{
var audioStreams = string.Join("", _multiFiles.Select((item, index) => $"[{index}:0]"));
var mixFilter = $"{audioStreams}amix=inputs={_multiFiles.Length}:duration=longest:dropout_transition=1:normalize=0[final]";
var ffmpegArgs = $"-filter_complex \"{mixFilter}\" -map \"[final]\"";
var str = FFMpegArguments
.FromFileInput(_multiFiles)
.OutputToFile("output.mp3", overwrite: true, options => options
.WithCustomArgument(ffmpegArgs)
.WithAudioCodec(AudioCodec.LibMp3Lame) // Set the audio codec to MP3
.WithAudioBitrate(128) // Set the bitrate to 128kbps
.WithAudioSamplingRate(48000) // Set the sample rate to 48kHz
.WithoutMetadata() // Remove metadata
.WithCustomArgument("-ac 2 -write_xing 0 -id3v2_version 0")) // Force 2 Channels
.Arguments;
Assert.AreEqual($"-i \"1.mp3\" -i \"2.mp3\" -i \"3.mp3\" -i \"4.mp3\" -filter_complex \"[0:0][1:0][2:0][3:0]amix=inputs=4:duration=longest:dropout_transition=1:normalize=0[final]\" -map \"[final]\" -c:a libmp3lame -b:a 128k -ar 48000 -map_metadata -1 -ac 2 -write_xing 0 -id3v2_version 0 \"output.mp3\" -y", str);
}
[TestMethod]
public void Pre_VerifyExists_AllFilesExist()
{
// Arrange
var filePaths = new List<string>
{
Path.GetTempFileName(),
Path.GetTempFileName(),
Path.GetTempFileName()
};
var argument = new MultiInputArgument(true, filePaths);
try
{
// Act & Assert
argument.Pre(); // No exception should be thrown
}
finally
{
// Cleanup
foreach (var filePath in filePaths)
{
File.Delete(filePath);
}
}
}
[TestMethod]
public void Pre_VerifyExists_SomeFilesNotExist()
{
// Arrange
var filePaths = new List<string>
{
Path.GetTempFileName(),
"file2.mp4",
"file3.mp4"
};
var argument = new MultiInputArgument(true, filePaths);
try
{
// Act & Assert
Assert.ThrowsException<FileNotFoundException>(() => argument.Pre());
}
finally
{
// Cleanup
File.Delete(filePaths[0]);
}
}
[TestMethod]
public void Pre_VerifyExists_NoFilesExist()
{
// Arrange
var filePaths = new List<string>
{
"file1.mp4",
"file2.mp4",
"file3.mp4"
};
var argument = new MultiInputArgument(true, filePaths);
// Act & Assert
Assert.ThrowsException<FileNotFoundException>(() => argument.Pre());
}
}
}

View file

@ -0,0 +1,47 @@
namespace FFMpegCore.Arguments
{
/// <summary>
/// Represents input parameters for multiple files
/// </summary>
public class MultiInputArgument : IInputArgument
{
public readonly bool VerifyExists;
public readonly IEnumerable<string> FilePaths;
public MultiInputArgument(bool verifyExists, IEnumerable<string> filePaths)
{
VerifyExists = verifyExists;
FilePaths = filePaths;
}
public MultiInputArgument(IEnumerable<string> filePaths, bool verifyExists) : this(verifyExists, filePaths) { }
public void Pre()
{
if (VerifyExists)
{
var missingFiles = new List<string>();
foreach (var filePath in FilePaths)
{
if (!File.Exists(filePath))
{
missingFiles.Add(filePath);
}
}
if (missingFiles.Any())
{
throw new FileNotFoundException($"The following input files were not found: {string.Join(", ", missingFiles)}");
}
}
}
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
public void Post() { }
/// <summary>
/// Generates a combined input argument text for all file paths
/// </summary>
public string Text => string.Join(" ", FilePaths.Select(filePath => $"-i \"{filePath}\""));
}
}

View file

@ -21,6 +21,7 @@ private string GetText()
public static FFMpegArguments FromConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments);
public static FFMpegArguments FromDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new DemuxConcatArgument(filePaths), addArguments);
public static FFMpegArguments FromFileInput(string filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(verifyExists, filePath), addArguments);
public static FFMpegArguments FromFileInput(IEnumerable<string> filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new MultiInputArgument(verifyExists, filePath), addArguments);
public static FFMpegArguments FromFileInput(FileInfo fileInfo, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(fileInfo.FullName, false), addArguments);
public static FFMpegArguments FromUrlInput(Uri uri, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputArgument(uri.AbsoluteUri, false), addArguments);
public static FFMpegArguments FromDeviceInput(string device, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputDeviceArgument(device), addArguments);
@ -35,6 +36,7 @@ public FFMpegArguments WithGlobalOptions(Action<FFMpegGlobalArguments> configure
public FFMpegArguments AddConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new ConcatArgument(filePaths), addArguments);
public FFMpegArguments AddDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new DemuxConcatArgument(filePaths), addArguments);
public FFMpegArguments AddFileInput(string filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new InputArgument(verifyExists, filePath), addArguments);
public FFMpegArguments AddFileInput(IEnumerable<string> filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new MultiInputArgument(verifyExists, filePath), addArguments);
public FFMpegArguments AddFileInput(FileInfo fileInfo, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new InputArgument(fileInfo.FullName, false), addArguments);
public FFMpegArguments AddUrlInput(Uri uri, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new InputArgument(uri.AbsoluteUri, false), addArguments);
public FFMpegArguments AddDeviceInput(string device, Action<FFMpegArgumentOptions>? addArguments = null) => WithInput(new InputDeviceArgument(device), addArguments);

View file

@ -3,7 +3,7 @@
<PropertyGroup>
<IsPackable>true</IsPackable>
<Description>A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications</Description>
<PackageVersion>5.1.0</PackageVersion>
<PackageVersion>5.1.1</PackageVersion>
<PackageOutputPath>../nupkg</PackageOutputPath>
<PackageReleaseNotes>
</PackageReleaseNotes>
@ -20,5 +20,7 @@
<PackageReference Include="Instances" Version="3.0.0" />
<PackageReference Include="System.Text.Json" Version="7.0.3" />
</ItemGroup>
</Project>