mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2025-12-14 18:15:44 +00:00
Run full code cleanup
This commit is contained in:
parent
d3d810ecd7
commit
ce87dc8a36
156 changed files with 8209 additions and 7627 deletions
|
|
@ -7,7 +7,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj" />
|
<ProjectReference Include="..\FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj"/>
|
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ var outputStream = new MemoryStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
FFMpeg.JoinImageSequence(@"..\joined_video.mp4", frameRate: 1, @"..\1.png", @"..\2.png", @"..\3.png");
|
FFMpeg.JoinImageSequence(@"..\joined_video.mp4", 1, @"..\1.png", @"..\2.png", @"..\3.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -90,7 +90,11 @@ var inputImagePath = "/path/to/input/image";
|
||||||
skiaSharpImage.AddAudio(inputAudioPath, outputPath);
|
skiaSharpImage.AddAudio(inputAudioPath, outputPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
IVideoFrame GetNextFrame() => throw new NotImplementedException();
|
IVideoFrame GetNextFrame()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
IEnumerable<IVideoFrame> CreateFrames(int count)
|
IEnumerable<IVideoFrame> CreateFrames(int count)
|
||||||
{
|
{
|
||||||
|
|
@ -100,7 +104,8 @@ IVideoFrame GetNextFrame() => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var videoFramesSource = new RawVideoPipeSource(CreateFrames(64)) //pass IEnumerable<IVideoFrame> or IEnumerator<IVideoFrame> to constructor of RawVideoPipeSource
|
var videoFramesSource =
|
||||||
|
new RawVideoPipeSource(CreateFrames(64)) //pass IEnumerable<IVideoFrame> or IEnumerator<IVideoFrame> to constructor of RawVideoPipeSource
|
||||||
{
|
{
|
||||||
FrameRate = 30 //set source frame rate
|
FrameRate = 30 //set source frame rate
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.SkiaSharp
|
namespace FFMpegCore.Extensions.SkiaSharp;
|
||||||
|
|
||||||
|
public static class BitmapExtensions
|
||||||
{
|
{
|
||||||
public static class BitmapExtensions
|
|
||||||
{
|
|
||||||
public static bool AddAudio(this SKBitmap poster, string audio, string output)
|
public static bool AddAudio(this SKBitmap poster, string audio, string output)
|
||||||
{
|
{
|
||||||
var destination = $"{Environment.TickCount}.png";
|
var destination = $"{Environment.TickCount}.png";
|
||||||
|
|
@ -24,5 +24,4 @@ namespace FFMpegCore.Extensions.SkiaSharp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,29 @@
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.SkiaSharp
|
namespace FFMpegCore.Extensions.SkiaSharp;
|
||||||
|
|
||||||
|
public class BitmapVideoFrameWrapper : IVideoFrame, IDisposable
|
||||||
{
|
{
|
||||||
public class BitmapVideoFrameWrapper : IVideoFrame, IDisposable
|
|
||||||
{
|
|
||||||
public int Width => Source.Width;
|
|
||||||
|
|
||||||
public int Height => Source.Height;
|
|
||||||
|
|
||||||
public string Format { get; private set; }
|
|
||||||
|
|
||||||
public SKBitmap Source { get; private set; }
|
|
||||||
|
|
||||||
public BitmapVideoFrameWrapper(SKBitmap bitmap)
|
public BitmapVideoFrameWrapper(SKBitmap bitmap)
|
||||||
{
|
{
|
||||||
Source = bitmap ?? throw new ArgumentNullException(nameof(bitmap));
|
Source = bitmap ?? throw new ArgumentNullException(nameof(bitmap));
|
||||||
Format = ConvertStreamFormat(bitmap.ColorType);
|
Format = ConvertStreamFormat(bitmap.ColorType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SKBitmap Source { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Source.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Width => Source.Width;
|
||||||
|
|
||||||
|
public int Height => Source.Height;
|
||||||
|
|
||||||
|
public string Format { get; }
|
||||||
|
|
||||||
public void Serialize(Stream stream)
|
public void Serialize(Stream stream)
|
||||||
{
|
{
|
||||||
var data = Source.Bytes;
|
var data = Source.Bytes;
|
||||||
|
|
@ -31,11 +36,6 @@ namespace FFMpegCore.Extensions.SkiaSharp
|
||||||
await stream.WriteAsync(data, 0, data.Length, token).ConfigureAwait(false);
|
await stream.WriteAsync(data, 0, data.Length, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Source.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ConvertStreamFormat(SKColorType fmt)
|
private static string ConvertStreamFormat(SKColorType fmt)
|
||||||
{
|
{
|
||||||
// TODO: Add support for additional formats
|
// TODO: Add support for additional formats
|
||||||
|
|
@ -55,5 +55,4 @@ namespace FFMpegCore.Extensions.SkiaSharp
|
||||||
throw new NotSupportedException($"Not supported pixel format {fmt}");
|
throw new NotSupportedException($"Not supported pixel format {fmt}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,12 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="SkiaSharp" Version="3.119.1" />
|
<PackageReference Include="SkiaSharp" Version="3.119.1"/>
|
||||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.1" />
|
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="3.119.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj" />
|
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.SkiaSharp
|
namespace FFMpegCore.Extensions.SkiaSharp;
|
||||||
|
|
||||||
|
public static class FFMpegImage
|
||||||
{
|
{
|
||||||
public static class FFMpegImage
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a 'png' thumbnail to an in-memory bitmap
|
/// Saves a 'png' thumbnail to an in-memory bitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -30,6 +30,7 @@ namespace FFMpegCore.Extensions.SkiaSharp
|
||||||
using var bitmap = SKBitmap.Decode(ms);
|
using var bitmap = SKBitmap.Decode(ms);
|
||||||
return bitmap.Copy();
|
return bitmap.Copy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a 'png' thumbnail to an in-memory bitmap
|
/// Saves a 'png' thumbnail to an in-memory bitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -39,7 +40,8 @@ namespace FFMpegCore.Extensions.SkiaSharp
|
||||||
/// <param name="streamIndex">Selected video stream index.</param>
|
/// <param name="streamIndex">Selected video stream index.</param>
|
||||||
/// <param name="inputFileIndex">Input file index</param>
|
/// <param name="inputFileIndex">Input file index</param>
|
||||||
/// <returns>Bitmap with the requested snapshot.</returns>
|
/// <returns>Bitmap with the requested snapshot.</returns>
|
||||||
public static async Task<SKBitmap> SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
|
public static async Task<SKBitmap> SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
|
||||||
|
int inputFileIndex = 0)
|
||||||
{
|
{
|
||||||
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
|
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
|
||||||
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
|
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
|
||||||
|
|
@ -53,5 +55,4 @@ namespace FFMpegCore.Extensions.SkiaSharp
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
return SKBitmap.Decode(ms);
|
return SKBitmap.Decode(ms);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.System.Drawing.Common
|
namespace FFMpegCore.Extensions.System.Drawing.Common;
|
||||||
|
|
||||||
|
public static class BitmapExtensions
|
||||||
{
|
{
|
||||||
public static class BitmapExtensions
|
|
||||||
{
|
|
||||||
public static bool AddAudio(this Image poster, string audio, string output)
|
public static bool AddAudio(this Image poster, string audio, string output)
|
||||||
{
|
{
|
||||||
var destination = $"{Environment.TickCount}.png";
|
var destination = $"{Environment.TickCount}.png";
|
||||||
|
|
@ -20,5 +20,4 @@ namespace FFMpegCore.Extensions.System.Drawing.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,29 @@ using System.Drawing.Imaging;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.System.Drawing.Common
|
namespace FFMpegCore.Extensions.System.Drawing.Common;
|
||||||
|
|
||||||
|
public class BitmapVideoFrameWrapper : IVideoFrame, IDisposable
|
||||||
{
|
{
|
||||||
public class BitmapVideoFrameWrapper : IVideoFrame, IDisposable
|
|
||||||
{
|
|
||||||
public int Width => Source.Width;
|
|
||||||
|
|
||||||
public int Height => Source.Height;
|
|
||||||
|
|
||||||
public string Format { get; private set; }
|
|
||||||
|
|
||||||
public Bitmap Source { get; private set; }
|
|
||||||
|
|
||||||
public BitmapVideoFrameWrapper(Bitmap bitmap)
|
public BitmapVideoFrameWrapper(Bitmap bitmap)
|
||||||
{
|
{
|
||||||
Source = bitmap ?? throw new ArgumentNullException(nameof(bitmap));
|
Source = bitmap ?? throw new ArgumentNullException(nameof(bitmap));
|
||||||
Format = ConvertStreamFormat(bitmap.PixelFormat);
|
Format = ConvertStreamFormat(bitmap.PixelFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bitmap Source { get; }
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Source.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Width => Source.Width;
|
||||||
|
|
||||||
|
public int Height => Source.Height;
|
||||||
|
|
||||||
|
public string Format { get; }
|
||||||
|
|
||||||
public void Serialize(Stream stream)
|
public void Serialize(Stream stream)
|
||||||
{
|
{
|
||||||
var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat);
|
var data = Source.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadOnly, Source.PixelFormat);
|
||||||
|
|
@ -53,11 +58,6 @@ namespace FFMpegCore.Extensions.System.Drawing.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Source.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ConvertStreamFormat(PixelFormat fmt)
|
private static string ConvertStreamFormat(PixelFormat fmt)
|
||||||
{
|
{
|
||||||
switch (fmt)
|
switch (fmt)
|
||||||
|
|
@ -83,5 +83,4 @@ namespace FFMpegCore.Extensions.System.Drawing.Common
|
||||||
throw new NotSupportedException($"Not supported pixel format {fmt}");
|
throw new NotSupportedException($"Not supported pixel format {fmt}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Drawing.Common" Version="9.0.10" />
|
<PackageReference Include="System.Drawing.Common" Version="9.0.10"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.System.Drawing.Common
|
namespace FFMpegCore.Extensions.System.Drawing.Common;
|
||||||
|
|
||||||
|
public static class FFMpegImage
|
||||||
{
|
{
|
||||||
public static class FFMpegImage
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a 'png' thumbnail to an in-memory bitmap
|
/// Saves a 'png' thumbnail to an in-memory bitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -39,7 +39,8 @@ namespace FFMpegCore.Extensions.System.Drawing.Common
|
||||||
/// <param name="streamIndex">Selected video stream index.</param>
|
/// <param name="streamIndex">Selected video stream index.</param>
|
||||||
/// <param name="inputFileIndex">Input file index</param>
|
/// <param name="inputFileIndex">Input file index</param>
|
||||||
/// <returns>Bitmap with the requested snapshot.</returns>
|
/// <returns>Bitmap with the requested snapshot.</returns>
|
||||||
public static async Task<Bitmap> SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
|
public static async Task<Bitmap> SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null,
|
||||||
|
int inputFileIndex = 0)
|
||||||
{
|
{
|
||||||
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
|
var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
|
||||||
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
|
var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
|
||||||
|
|
@ -53,5 +54,4 @@ namespace FFMpegCore.Extensions.System.Drawing.Common
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
return new Bitmap(ms);
|
return new Bitmap(ms);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using FFMpegCore.Arguments;
|
using FFMpegCore.Arguments;
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class ArgumentBuilderTest
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class ArgumentBuilderTest
|
|
||||||
{
|
|
||||||
private readonly string[] _concatFiles = { "1.mp4", "2.mp4", "3.mp4", "4.mp4" };
|
private readonly string[] _concatFiles = { "1.mp4", "2.mp4", "3.mp4", "4.mp4" };
|
||||||
private readonly string[] _multiFiles = { "1.mp3", "2.mp3", "3.mp3", "4.mp3" };
|
private readonly string[] _multiFiles = { "1.mp3", "2.mp3", "3.mp3", "4.mp3" };
|
||||||
|
|
||||||
|
|
@ -256,14 +255,16 @@ namespace FFMpegCore.Test
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Builder_BuildString_Seek()
|
public void Builder_BuildString_Seek()
|
||||||
{
|
{
|
||||||
var str = FFMpegArguments.FromFileInput("input.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10))).OutputToFile("output.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10))).Arguments;
|
var str = FFMpegArguments.FromFileInput("input.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10)))
|
||||||
|
.OutputToFile("output.mp4", false, opt => opt.Seek(TimeSpan.FromSeconds(10))).Arguments;
|
||||||
Assert.AreEqual("-ss 00:00:10.000 -i \"input.mp4\" -ss 00:00:10.000 \"output.mp4\"", str);
|
Assert.AreEqual("-ss 00:00:10.000 -i \"input.mp4\" -ss 00:00:10.000 \"output.mp4\"", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Builder_BuildString_EndSeek()
|
public void Builder_BuildString_EndSeek()
|
||||||
{
|
{
|
||||||
var str = FFMpegArguments.FromFileInput("input.mp4", false, opt => opt.EndSeek(TimeSpan.FromSeconds(10))).OutputToFile("output.mp4", false, opt => opt.EndSeek(TimeSpan.FromSeconds(10))).Arguments;
|
var str = FFMpegArguments.FromFileInput("input.mp4", false, opt => opt.EndSeek(TimeSpan.FromSeconds(10)))
|
||||||
|
.OutputToFile("output.mp4", false, opt => opt.EndSeek(TimeSpan.FromSeconds(10))).Arguments;
|
||||||
Assert.AreEqual("-to 00:00:10.000 -i \"input.mp4\" -to 00:00:10.000 \"output.mp4\"", str);
|
Assert.AreEqual("-to 00:00:10.000 -i \"input.mp4\" -to 00:00:10.000 \"output.mp4\"", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,7 +339,7 @@ namespace FFMpegCore.Test
|
||||||
.OutputToFile("output.mp4", false, opt => opt
|
.OutputToFile("output.mp4", false, opt => opt
|
||||||
.WithVideoFilters(filterOptions => filterOptions
|
.WithVideoFilters(filterOptions => filterOptions
|
||||||
.HardBurnSubtitle(SubtitleHardBurnOptions
|
.HardBurnSubtitle(SubtitleHardBurnOptions
|
||||||
.Create(subtitlePath: "sample.srt")
|
.Create("sample.srt")
|
||||||
.SetCharacterEncoding("UTF-8")
|
.SetCharacterEncoding("UTF-8")
|
||||||
.SetOriginalSize(1366, 768)
|
.SetOriginalSize(1366, 768)
|
||||||
.SetSubtitleIndex(0)
|
.SetSubtitleIndex(0)
|
||||||
|
|
@ -347,7 +348,8 @@ namespace FFMpegCore.Test
|
||||||
.WithParameter("PrimaryColour", "&HAA00FF00")))))
|
.WithParameter("PrimaryColour", "&HAA00FF00")))))
|
||||||
.Arguments;
|
.Arguments;
|
||||||
|
|
||||||
Assert.AreEqual("-i \"input.mp4\" -vf \"subtitles='sample.srt':charenc=UTF-8:original_size=1366x768:stream_index=0:force_style='FontName=DejaVu Serif\\,PrimaryColour=&HAA00FF00'\" \"output.mp4\"",
|
Assert.AreEqual(
|
||||||
|
"-i \"input.mp4\" -vf \"subtitles='sample.srt':charenc=UTF-8:original_size=1366x768:stream_index=0:force_style='FontName=DejaVu Serif\\,PrimaryColour=&HAA00FF00'\" \"output.mp4\"",
|
||||||
str);
|
str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -359,7 +361,7 @@ namespace FFMpegCore.Test
|
||||||
.OutputToFile("output.mp4", false, opt => opt
|
.OutputToFile("output.mp4", false, opt => opt
|
||||||
.WithVideoFilters(filterOptions => filterOptions
|
.WithVideoFilters(filterOptions => filterOptions
|
||||||
.HardBurnSubtitle(SubtitleHardBurnOptions
|
.HardBurnSubtitle(SubtitleHardBurnOptions
|
||||||
.Create(subtitlePath: @"sample( \ : [ ] , ' ).srt"))))
|
.Create(@"sample( \ : [ ] , ' ).srt"))))
|
||||||
.Arguments;
|
.Arguments;
|
||||||
|
|
||||||
Assert.AreEqual(@"-i ""input.mp4"" -vf ""subtitles='sample( \\ \: \[ \] \, '\\\'' ).srt'"" ""output.mp4""",
|
Assert.AreEqual(@"-i ""input.mp4"" -vf ""subtitles='sample( \\ \: \[ \] \, '\\\'' ).srt'"" ""output.mp4""",
|
||||||
|
|
@ -494,7 +496,7 @@ namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
var str = FFMpegArguments.FromFileInput("input.aaxc", false, x => x.WithAudibleEncryptionKeys("123", "456"))
|
var str = FFMpegArguments.FromFileInput("input.aaxc", false, x => x.WithAudibleEncryptionKeys("123", "456"))
|
||||||
.MapMetaData()
|
.MapMetaData()
|
||||||
.OutputToFile("output.m4b", true, x => x.WithTagVersion(3).DisableChannel(Channel.Video).CopyChannel(Channel.Audio))
|
.OutputToFile("output.m4b", true, x => x.WithTagVersion().DisableChannel(Channel.Video).CopyChannel(Channel.Audio))
|
||||||
.Arguments;
|
.Arguments;
|
||||||
|
|
||||||
Assert.AreEqual("-audible_key 123 -audible_iv 456 -i \"input.aaxc\" -map_metadata 0 -id3v2_version 3 -vn -c:a copy \"output.m4b\" -y", str);
|
Assert.AreEqual("-audible_key 123 -audible_iv 456 -i \"input.aaxc\" -map_metadata 0 -id3v2_version 3 -vn -c:a copy \"output.m4b\" -y", str);
|
||||||
|
|
@ -578,13 +580,11 @@ namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
var str = FFMpegArguments.FromFileInput("input.mp4")
|
var str = FFMpegArguments.FromFileInput("input.mp4")
|
||||||
.MultiOutput(args => args
|
.MultiOutput(args => args
|
||||||
.OutputToFile("output.mp4", overwrite: true, args => args.CopyChannel())
|
.OutputToFile("output.mp4", true, args => args.CopyChannel())
|
||||||
.OutputToFile("output.ts", overwrite: false, args => args.CopyChannel().ForceFormat("mpegts"))
|
.OutputToFile("output.ts", false, args => args.CopyChannel().ForceFormat("mpegts"))
|
||||||
.OutputToUrl("http://server/path", options => options.ForceFormat("webm")))
|
.OutputToUrl("http://server/path", options => options.ForceFormat("webm")))
|
||||||
.Arguments;
|
.Arguments;
|
||||||
Assert.AreEqual($"""
|
Assert.AreEqual("""-i "input.mp4" -c:a copy -c:v copy "output.mp4" -y -c:a copy -c:v copy -f mpegts "output.ts" -f webm http://server/path""", str);
|
||||||
-i "input.mp4" -c:a copy -c:v copy "output.mp4" -y -c:a copy -c:v copy -f mpegts "output.ts" -f webm http://server/path
|
|
||||||
""", str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
@ -592,10 +592,10 @@ namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
var str = FFMpegArguments.FromFileInput("input.mp4")
|
var str = FFMpegArguments.FromFileInput("input.mp4")
|
||||||
.MultiOutput(args => args
|
.MultiOutput(args => args
|
||||||
.OutputToFile("sd.mp4", overwrite: true, args => args.Resize(1200, 720))
|
.OutputToFile("sd.mp4", true, args => args.Resize(1200, 720))
|
||||||
.OutputToFile("hd.mp4", overwrite: false, args => args.Resize(1920, 1080)))
|
.OutputToFile("hd.mp4", false, args => args.Resize(1920, 1080)))
|
||||||
.Arguments;
|
.Arguments;
|
||||||
Assert.AreEqual($"""
|
Assert.AreEqual("""
|
||||||
-i "input.mp4" -s 1200x720 "sd.mp4" -y -s 1920x1080 "hd.mp4"
|
-i "input.mp4" -s 1200x720 "sd.mp4" -y -s 1920x1080 "hd.mp4"
|
||||||
""", str);
|
""", str);
|
||||||
}
|
}
|
||||||
|
|
@ -605,13 +605,14 @@ namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
var str = FFMpegArguments.FromFileInput("input.mp4")
|
var str = FFMpegArguments.FromFileInput("input.mp4")
|
||||||
.OutputToTee(args => args
|
.OutputToTee(args => args
|
||||||
.OutputToFile("output.mp4", overwrite: false, args => args.WithFastStart())
|
.OutputToFile("output.mp4", false, args => args.WithFastStart())
|
||||||
.OutputToUrl("http://server/path", options => options.ForceFormat("mpegts").SelectStream(0, channel: Channel.Video)))
|
.OutputToUrl("http://server/path", options => options.ForceFormat("mpegts").SelectStream(0, channel: Channel.Video)))
|
||||||
.Arguments;
|
.Arguments;
|
||||||
Assert.AreEqual($"""
|
Assert.AreEqual("""
|
||||||
-i "input.mp4" -f tee "[movflags=faststart]output.mp4|[f=mpegts:select=\'0:v:0\']http://server/path"
|
-i "input.mp4" -f tee "[movflags=faststart]output.mp4|[f=mpegts:select=\'0:v:0\']http://server/path"
|
||||||
""", str);
|
""", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Builder_BuildString_MultiInput()
|
public void Builder_BuildString_MultiInput()
|
||||||
{
|
{
|
||||||
|
|
@ -620,26 +621,24 @@ namespace FFMpegCore.Test
|
||||||
var ffmpegArgs = $"-filter_complex \"{mixFilter}\" -map \"[final]\"";
|
var ffmpegArgs = $"-filter_complex \"{mixFilter}\" -map \"[final]\"";
|
||||||
var str = FFMpegArguments
|
var str = FFMpegArguments
|
||||||
.FromFileInput(_multiFiles)
|
.FromFileInput(_multiFiles)
|
||||||
.OutputToFile("output.mp3", overwrite: true, options => options
|
.OutputToFile("output.mp3", true, options => options
|
||||||
.WithCustomArgument(ffmpegArgs)
|
.WithCustomArgument(ffmpegArgs)
|
||||||
.WithAudioCodec(AudioCodec.LibMp3Lame) // Set the audio codec to MP3
|
.WithAudioCodec(AudioCodec.LibMp3Lame) // Set the audio codec to MP3
|
||||||
.WithAudioBitrate(128) // Set the bitrate to 128kbps
|
.WithAudioBitrate(128) // Set the bitrate to 128kbps
|
||||||
.WithAudioSamplingRate(48000) // Set the sample rate to 48kHz
|
.WithAudioSamplingRate() // Set the sample rate to 48kHz
|
||||||
.WithoutMetadata() // Remove metadata
|
.WithoutMetadata() // Remove metadata
|
||||||
.WithCustomArgument("-ac 2 -write_xing 0 -id3v2_version 0")) // Force 2 Channels
|
.WithCustomArgument("-ac 2 -write_xing 0 -id3v2_version 0")) // Force 2 Channels
|
||||||
.Arguments;
|
.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);
|
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]
|
[TestMethod]
|
||||||
public void Pre_VerifyExists_AllFilesExist()
|
public void Pre_VerifyExists_AllFilesExist()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filePaths = new List<string>
|
var filePaths = new List<string> { Path.GetTempFileName(), Path.GetTempFileName(), Path.GetTempFileName() };
|
||||||
{
|
|
||||||
Path.GetTempFileName(),
|
|
||||||
Path.GetTempFileName(),
|
|
||||||
Path.GetTempFileName()
|
|
||||||
};
|
|
||||||
var argument = new MultiInputArgument(true, filePaths);
|
var argument = new MultiInputArgument(true, filePaths);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -660,12 +659,7 @@ namespace FFMpegCore.Test
|
||||||
public void Pre_VerifyExists_SomeFilesNotExist()
|
public void Pre_VerifyExists_SomeFilesNotExist()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filePaths = new List<string>
|
var filePaths = new List<string> { Path.GetTempFileName(), "file2.mp4", "file3.mp4" };
|
||||||
{
|
|
||||||
Path.GetTempFileName(),
|
|
||||||
"file2.mp4",
|
|
||||||
"file3.mp4"
|
|
||||||
};
|
|
||||||
var argument = new MultiInputArgument(true, filePaths);
|
var argument = new MultiInputArgument(true, filePaths);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -683,15 +677,9 @@ namespace FFMpegCore.Test
|
||||||
public void Pre_VerifyExists_NoFilesExist()
|
public void Pre_VerifyExists_NoFilesExist()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var filePaths = new List<string>
|
var filePaths = new List<string> { "file1.mp4", "file2.mp4", "file3.mp4" };
|
||||||
{
|
|
||||||
"file1.mp4",
|
|
||||||
"file2.mp4",
|
|
||||||
"file3.mp4"
|
|
||||||
};
|
|
||||||
var argument = new MultiInputArgument(true, filePaths);
|
var argument = new MultiInputArgument(true, filePaths);
|
||||||
// Act & Assert
|
// Act & Assert
|
||||||
Assert.ThrowsExactly<FileNotFoundException>(() => argument.Pre());
|
Assert.ThrowsExactly<FileNotFoundException>(() => argument.Pre());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ using FFMpegCore.Extend;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
using FFMpegCore.Test.Resources;
|
using FFMpegCore.Test.Resources;
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class AudioTest
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class AudioTest
|
|
||||||
{
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Audio_Remove()
|
public void Audio_Remove()
|
||||||
{
|
{
|
||||||
|
|
@ -69,23 +69,15 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(File.Exists(outputFile));
|
Assert.IsTrue(File.Exists(outputFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_ToAAC_Args_Pipe()
|
public void Audio_ToAAC_Args_Pipe()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
var samples = new List<IAudioSample>
|
var samples = new List<IAudioSample> { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) };
|
||||||
{
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
};
|
|
||||||
|
|
||||||
var audioSamplesSource = new RawAudioPipeSource(samples)
|
var audioSamplesSource = new RawAudioPipeSource(samples) { Channels = 2, Format = "s8", SampleRate = 8000 };
|
||||||
{
|
|
||||||
Channels = 2,
|
|
||||||
Format = "s8",
|
|
||||||
SampleRate = 8000,
|
|
||||||
};
|
|
||||||
|
|
||||||
var success = FFMpegArguments
|
var success = FFMpegArguments
|
||||||
.FromPipeInput(audioSamplesSource)
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
|
@ -95,23 +87,15 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_ToLibVorbis_Args_Pipe()
|
public void Audio_ToLibVorbis_Args_Pipe()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
var samples = new List<IAudioSample>
|
var samples = new List<IAudioSample> { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) };
|
||||||
{
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
};
|
|
||||||
|
|
||||||
var audioSamplesSource = new RawAudioPipeSource(samples)
|
var audioSamplesSource = new RawAudioPipeSource(samples) { Channels = 2, Format = "s8", SampleRate = 8000 };
|
||||||
{
|
|
||||||
Channels = 2,
|
|
||||||
Format = "s8",
|
|
||||||
SampleRate = 8000,
|
|
||||||
};
|
|
||||||
|
|
||||||
var success = FFMpegArguments
|
var success = FFMpegArguments
|
||||||
.FromPipeInput(audioSamplesSource)
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
|
@ -121,23 +105,15 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Audio_ToAAC_Args_Pipe_Async()
|
public async Task Audio_ToAAC_Args_Pipe_Async()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
var samples = new List<IAudioSample>
|
var samples = new List<IAudioSample> { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) };
|
||||||
{
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
};
|
|
||||||
|
|
||||||
var audioSamplesSource = new RawAudioPipeSource(samples)
|
var audioSamplesSource = new RawAudioPipeSource(samples) { Channels = 2, Format = "s8", SampleRate = 8000 };
|
||||||
{
|
|
||||||
Channels = 2,
|
|
||||||
Format = "s8",
|
|
||||||
SampleRate = 8000,
|
|
||||||
};
|
|
||||||
|
|
||||||
var success = await FFMpegArguments
|
var success = await FFMpegArguments
|
||||||
.FromPipeInput(audioSamplesSource)
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
|
@ -147,16 +123,13 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_ToAAC_Args_Pipe_ValidDefaultConfiguration()
|
public void Audio_ToAAC_Args_Pipe_ValidDefaultConfiguration()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
var samples = new List<IAudioSample>
|
var samples = new List<IAudioSample> { new PcmAudioSampleWrapper([0, 0]), new PcmAudioSampleWrapper([0, 0]) };
|
||||||
{
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
new PcmAudioSampleWrapper([0, 0]),
|
|
||||||
};
|
|
||||||
|
|
||||||
var audioSamplesSource = new RawAudioPipeSource(samples);
|
var audioSamplesSource = new RawAudioPipeSource(samples);
|
||||||
|
|
||||||
|
|
@ -168,15 +141,13 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_ToAAC_Args_Pipe_InvalidChannels()
|
public void Audio_ToAAC_Args_Pipe_InvalidChannels()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>())
|
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>()) { Channels = 0 };
|
||||||
{
|
|
||||||
Channels = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.ThrowsExactly<FFMpegException>(() => FFMpegArguments
|
Assert.ThrowsExactly<FFMpegException>(() => FFMpegArguments
|
||||||
.FromPipeInput(audioSamplesSource)
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
|
@ -185,15 +156,13 @@ namespace FFMpegCore.Test
|
||||||
.ProcessSynchronously());
|
.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_ToAAC_Args_Pipe_InvalidFormat()
|
public void Audio_ToAAC_Args_Pipe_InvalidFormat()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>())
|
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>()) { Format = "s8le" };
|
||||||
{
|
|
||||||
Format = "s8le",
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.ThrowsExactly<FFMpegException>(() => FFMpegArguments
|
Assert.ThrowsExactly<FFMpegException>(() => FFMpegArguments
|
||||||
.FromPipeInput(audioSamplesSource)
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
|
@ -202,15 +171,13 @@ namespace FFMpegCore.Test
|
||||||
.ProcessSynchronously());
|
.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_ToAAC_Args_Pipe_InvalidSampleRate()
|
public void Audio_ToAAC_Args_Pipe_InvalidSampleRate()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
||||||
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>())
|
var audioSamplesSource = new RawAudioPipeSource(new List<IAudioSample>()) { SampleRate = 0 };
|
||||||
{
|
|
||||||
SampleRate = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.ThrowsExactly<FFMpegException>(() => FFMpegArguments
|
Assert.ThrowsExactly<FFMpegException>(() => FFMpegArguments
|
||||||
.FromPipeInput(audioSamplesSource)
|
.FromPipeInput(audioSamplesSource)
|
||||||
|
|
@ -219,7 +186,8 @@ namespace FFMpegCore.Test
|
||||||
.ProcessSynchronously());
|
.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_Pan_ToMono()
|
public void Audio_Pan_ToMono()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -237,7 +205,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout);
|
Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_Pan_ToMonoNoDefinitions()
|
public void Audio_Pan_ToMonoNoDefinitions()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -255,7 +224,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout);
|
Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_Pan_ToMonoChannelsToOutputDefinitionsMismatch()
|
public void Audio_Pan_ToMonoChannelsToOutputDefinitionsMismatch()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -267,7 +237,8 @@ namespace FFMpegCore.Test
|
||||||
.ProcessSynchronously());
|
.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_Pan_ToMonoChannelsLayoutToOutputDefinitionsMismatch()
|
public void Audio_Pan_ToMonoChannelsLayoutToOutputDefinitionsMismatch()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -279,7 +250,8 @@ namespace FFMpegCore.Test
|
||||||
.ProcessSynchronously());
|
.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_DynamicNormalizer_WithDefaultValues()
|
public void Audio_DynamicNormalizer_WithDefaultValues()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -293,7 +265,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Audio_DynamicNormalizer_WithNonDefaultValues()
|
public void Audio_DynamicNormalizer_WithNonDefaultValues()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -301,14 +274,14 @@ namespace FFMpegCore.Test
|
||||||
var success = FFMpegArguments.FromFileInput(TestResources.Mp3Audio)
|
var success = FFMpegArguments.FromFileInput(TestResources.Mp3Audio)
|
||||||
.OutputToFile(outputFile, true,
|
.OutputToFile(outputFile, true,
|
||||||
argumentOptions => argumentOptions
|
argumentOptions => argumentOptions
|
||||||
.WithAudioFilters(
|
.WithAudioFilters(filter => filter.DynamicNormalizer(250, 7, 0.9, 2, 1, false, true, true, 0.5)))
|
||||||
filter => filter.DynamicNormalizer(250, 7, 0.9, 2, 1, false, true, true, 0.5)))
|
|
||||||
.ProcessSynchronously();
|
.ProcessSynchronously();
|
||||||
|
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
[DataRow(2)]
|
[DataRow(2)]
|
||||||
[DataRow(32)]
|
[DataRow(32)]
|
||||||
[DataRow(8)]
|
[DataRow(8)]
|
||||||
|
|
@ -320,9 +293,7 @@ namespace FFMpegCore.Test
|
||||||
.FromFileInput(TestResources.Mp3Audio)
|
.FromFileInput(TestResources.Mp3Audio)
|
||||||
.OutputToFile(outputFile, true,
|
.OutputToFile(outputFile, true,
|
||||||
argumentOptions => argumentOptions
|
argumentOptions => argumentOptions
|
||||||
.WithAudioFilters(
|
.WithAudioFilters(filter => filter.DynamicNormalizer(filterWindow: filterWindow)))
|
||||||
filter => filter.DynamicNormalizer(filterWindow: filterWindow)))
|
|
||||||
.ProcessSynchronously());
|
.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using FFMpegCore.Arguments;
|
using FFMpegCore.Arguments;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class FFMpegArgumentProcessorTest
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class FFMpegArgumentProcessorTest
|
|
||||||
{
|
|
||||||
[TestCleanup]
|
[TestCleanup]
|
||||||
public void TestInitialize()
|
public void TestInitialize()
|
||||||
|
|
||||||
|
|
@ -16,9 +15,12 @@ namespace FFMpegCore.Test
|
||||||
typeof(GlobalFFOptions).GetField("_current", BindingFlags.NonPublic | BindingFlags.Static)!.SetValue(GlobalFFOptions.Current, null);
|
typeof(GlobalFFOptions).GetField("_current", BindingFlags.NonPublic | BindingFlags.Static)!.SetValue(GlobalFFOptions.Current, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FFMpegArgumentProcessor CreateArgumentProcessor() => FFMpegArguments
|
private static FFMpegArgumentProcessor CreateArgumentProcessor()
|
||||||
|
{
|
||||||
|
return FFMpegArguments
|
||||||
.FromFileInput("")
|
.FromFileInput("")
|
||||||
.OutputToFile("");
|
.OutputToFile("");
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Processor_GlobalOptions_GetUsed()
|
public void Processor_GlobalOptions_GetUsed()
|
||||||
|
|
@ -54,7 +56,7 @@ namespace FFMpegCore.Test
|
||||||
var sessionTempDir = "./CurrentRunWorkingDir";
|
var sessionTempDir = "./CurrentRunWorkingDir";
|
||||||
processor.Configure(options => options.TemporaryFilesFolder = sessionTempDir);
|
processor.Configure(options => options.TemporaryFilesFolder = sessionTempDir);
|
||||||
|
|
||||||
var overrideOptions = new FFOptions() { WorkingDirectory = "override" };
|
var overrideOptions = new FFOptions { WorkingDirectory = "override" };
|
||||||
var options = processor.GetConfiguredOptions(overrideOptions);
|
var options = processor.GetConfiguredOptions(overrideOptions);
|
||||||
|
|
||||||
options.Should().BeEquivalentTo(overrideOptions);
|
options.Should().BeEquivalentTo(overrideOptions);
|
||||||
|
|
@ -83,21 +85,20 @@ namespace FFMpegCore.Test
|
||||||
public void Concat_Escape()
|
public void Concat_Escape()
|
||||||
{
|
{
|
||||||
var arg = new DemuxConcatArgument(new[] { @"Heaven's River\05 - Investigation.m4b" });
|
var arg = new DemuxConcatArgument(new[] { @"Heaven's River\05 - Investigation.m4b" });
|
||||||
arg.Values.Should().BeEquivalentTo(new[] { @"file 'Heaven'\''s River\05 - Investigation.m4b'" });
|
arg.Values.Should().BeEquivalentTo(@"file 'Heaven'\''s River\05 - Investigation.m4b'");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Audible_Aaxc_Test()
|
public void Audible_Aaxc_Test()
|
||||||
{
|
{
|
||||||
var arg = new AudibleEncryptionKeyArgument("123", "456");
|
var arg = new AudibleEncryptionKeyArgument("123", "456");
|
||||||
arg.Text.Should().Be($"-audible_key 123 -audible_iv 456");
|
arg.Text.Should().Be("-audible_key 123 -audible_iv 456");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Audible_Aax_Test()
|
public void Audible_Aax_Test()
|
||||||
{
|
{
|
||||||
var arg = new AudibleEncryptionKeyArgument("62689101");
|
var arg = new AudibleEncryptionKeyArgument("62689101");
|
||||||
arg.Text.Should().Be($"-activation_bytes 62689101");
|
arg.Text.Should().Be("-activation_bytes 62689101");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,21 +12,21 @@
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="FluentAssertions" Version="8.7.1" />
|
<PackageReference Include="FluentAssertions" Version="8.7.1"/>
|
||||||
<PackageReference Include="GitHubActionsTestLogger" Version="2.4.1">
|
<PackageReference Include="GitHubActionsTestLogger" Version="2.4.1">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0"/>
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="4.0.1" />
|
<PackageReference Include="MSTest.TestAdapter" Version="4.0.1"/>
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="4.0.1" />
|
<PackageReference Include="MSTest.TestFramework" Version="4.0.1"/>
|
||||||
<PackageReference Include="SkiaSharp" Version="3.119.1" />
|
<PackageReference Include="SkiaSharp" Version="3.119.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj" />
|
<ProjectReference Include="..\FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj" />
|
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj" />
|
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class FFMpegOptionsTest
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class FFMpegOptionsTest
|
|
||||||
{
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Options_Initialized()
|
public void Options_Initialized()
|
||||||
{
|
{
|
||||||
|
|
@ -44,5 +43,4 @@ namespace FFMpegCore.Test
|
||||||
GlobalFFOptions.Configure(original);
|
GlobalFFOptions.Configure(original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
using FFMpegCore.Test.Resources;
|
using FFMpegCore.Test.Resources;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class FFProbeTests
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class FFProbeTests
|
|
||||||
{
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public async Task Audio_FromStream_Duration()
|
public async Task Audio_FromStream_Duration()
|
||||||
{
|
{
|
||||||
|
|
@ -80,7 +79,8 @@ namespace FFMpegCore.Test
|
||||||
[DataRow("05:12:59.177", 0, 5, 12, 59, 177)]
|
[DataRow("05:12:59.177", 0, 5, 12, 59, 177)]
|
||||||
[DataRow("149:07:50.911750", 6, 5, 7, 50, 911)]
|
[DataRow("149:07:50.911750", 6, 5, 7, 50, 911)]
|
||||||
[DataRow("00:00:00.83", 0, 0, 0, 0, 830)]
|
[DataRow("00:00:00.83", 0, 0, 0, 0, 830)]
|
||||||
public void MediaAnalysis_ParseDuration(string duration, int expectedDays, int expectedHours, int expectedMinutes, int expectedSeconds, int expectedMilliseconds)
|
public void MediaAnalysis_ParseDuration(string duration, int expectedDays, int expectedHours, int expectedMinutes, int expectedSeconds,
|
||||||
|
int expectedMilliseconds)
|
||||||
{
|
{
|
||||||
var ffprobeStream = new FFProbeStream { Duration = duration };
|
var ffprobeStream = new FFProbeStream { Duration = duration };
|
||||||
|
|
||||||
|
|
@ -93,7 +93,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(expectedMilliseconds, parsedDuration.Milliseconds);
|
Assert.AreEqual(expectedMilliseconds, parsedDuration.Milliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Ignore("Consistently fails on GitHub Workflow ubuntu agents")]
|
[TestMethod]
|
||||||
|
[Ignore("Consistently fails on GitHub Workflow ubuntu agents")]
|
||||||
public async Task Uri_Duration()
|
public async Task Uri_Duration()
|
||||||
{
|
{
|
||||||
var fileAnalysis = await FFProbe.AnalyseAsync(new Uri("https://github.com/rosenbjerg/FFMpegCore/raw/master/FFMpegCore.Test/Resources/input_3sec.webm"));
|
var fileAnalysis = await FFProbe.AnalyseAsync(new Uri("https://github.com/rosenbjerg/FFMpegCore/raw/master/FFMpegCore.Test/Resources/input_3sec.webm"));
|
||||||
|
|
@ -156,7 +157,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(-90, info.PrimaryVideoStream.Rotation);
|
Assert.AreEqual(-90, info.PrimaryVideoStream.Rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Async_Success()
|
public async Task Probe_Async_Success()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.Mp4Video);
|
var info = await FFProbe.AnalyseAsync(TestResources.Mp4Video);
|
||||||
|
|
@ -168,7 +170,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsNull(info.PrimaryAudioStream.BitDepth);
|
Assert.IsNull(info.PrimaryAudioStream.BitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Probe_Success_FromStream()
|
public void Probe_Success_FromStream()
|
||||||
{
|
{
|
||||||
using var stream = File.OpenRead(TestResources.WebmVideo);
|
using var stream = File.OpenRead(TestResources.WebmVideo);
|
||||||
|
|
@ -178,7 +181,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsNull(info.PrimaryAudioStream);
|
Assert.IsNull(info.PrimaryAudioStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_FromStream_Async()
|
public async Task Probe_Success_FromStream_Async()
|
||||||
{
|
{
|
||||||
await using var stream = File.OpenRead(TestResources.WebmVideo);
|
await using var stream = File.OpenRead(TestResources.WebmVideo);
|
||||||
|
|
@ -186,7 +190,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(3, info.Duration.Seconds);
|
Assert.AreEqual(3, info.Duration.Seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public void Probe_HDR()
|
public void Probe_HDR()
|
||||||
{
|
{
|
||||||
var info = FFProbe.Analyse(TestResources.HdrVideo);
|
var info = FFProbe.Analyse(TestResources.HdrVideo);
|
||||||
|
|
@ -198,7 +203,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("bt2020", info.PrimaryVideoStream.ColorPrimaries);
|
Assert.AreEqual("bt2020", info.PrimaryVideoStream.ColorPrimaries);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_Subtitle_Async()
|
public async Task Probe_Success_Subtitle_Async()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.SrtSubtitle);
|
var info = await FFProbe.AnalyseAsync(TestResources.SrtSubtitle);
|
||||||
|
|
@ -210,7 +216,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsNull(info.SubtitleStreams[0].BitDepth);
|
Assert.IsNull(info.SubtitleStreams[0].BitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_Disposition_Async()
|
public async Task Probe_Success_Disposition_Async()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.Mp4Video);
|
var info = await FFProbe.AnalyseAsync(TestResources.Mp4Video);
|
||||||
|
|
@ -220,7 +227,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsFalse(info.PrimaryAudioStream.Disposition["forced"]);
|
Assert.IsFalse(info.PrimaryAudioStream.Disposition["forced"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_Mp3AudioBitDepthNull_Async()
|
public async Task Probe_Success_Mp3AudioBitDepthNull_Async()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.Mp3Audio);
|
var info = await FFProbe.AnalyseAsync(TestResources.Mp3Audio);
|
||||||
|
|
@ -229,7 +237,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsNull(info.PrimaryAudioStream.BitDepth);
|
Assert.IsNull(info.PrimaryAudioStream.BitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_VocAudioBitDepth_Async()
|
public async Task Probe_Success_VocAudioBitDepth_Async()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.AiffAudio);
|
var info = await FFProbe.AnalyseAsync(TestResources.AiffAudio);
|
||||||
|
|
@ -237,7 +246,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(16, info.PrimaryAudioStream.BitDepth);
|
Assert.AreEqual(16, info.PrimaryAudioStream.BitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_MkvVideoBitDepth_Async()
|
public async Task Probe_Success_MkvVideoBitDepth_Async()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.MkvVideo);
|
var info = await FFProbe.AnalyseAsync(TestResources.MkvVideo);
|
||||||
|
|
@ -248,7 +258,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsNull(info.PrimaryAudioStream.BitDepth);
|
Assert.IsNull(info.PrimaryAudioStream.BitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_24BitWavBitDepth_Async()
|
public async Task Probe_Success_24BitWavBitDepth_Async()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.Wav24Bit);
|
var info = await FFProbe.AnalyseAsync(TestResources.Wav24Bit);
|
||||||
|
|
@ -256,7 +267,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(24, info.PrimaryAudioStream.BitDepth);
|
Assert.AreEqual(24, info.PrimaryAudioStream.BitDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(10000, CooperativeCancellation = true)]
|
||||||
public async Task Probe_Success_32BitWavBitDepth_Async()
|
public async Task Probe_Success_32BitWavBitDepth_Async()
|
||||||
{
|
{
|
||||||
var info = await FFProbe.AnalyseAsync(TestResources.Wav32Bit);
|
var info = await FFProbe.AnalyseAsync(TestResources.Wav32Bit);
|
||||||
|
|
@ -270,5 +282,4 @@ namespace FFMpegCore.Test
|
||||||
var info = FFProbe.Analyse(TestResources.Mp4Video, customArguments: "-headers \"Hello: World\"");
|
var info = FFProbe.Analyse(TestResources.Mp4Video, customArguments: "-headers \"Hello: World\"");
|
||||||
Assert.AreEqual(3, info.Duration.Seconds);
|
Assert.AreEqual(3, info.Duration.Seconds);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using FFMpegCore.Builders.MetaData;
|
using FFMpegCore.Builders.MetaData;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class MetaDataBuilderTests
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class MetaDataBuilderTests
|
|
||||||
{
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void TestMetaDataBuilderIntegrity()
|
public void TestMetaDataBuilderIntegrity()
|
||||||
{
|
{
|
||||||
|
|
@ -20,10 +19,8 @@ namespace FFMpegCore.Test
|
||||||
Genres = new[] { "Synthwave", "Classics" },
|
Genres = new[] { "Synthwave", "Classics" },
|
||||||
Tracks = new[]
|
Tracks = new[]
|
||||||
{
|
{
|
||||||
new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 01" },
|
new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 01" }, new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 02" },
|
||||||
new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 02" },
|
new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 03" }, new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 04" }
|
||||||
new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 03" },
|
|
||||||
new { Duration = TimeSpan.FromSeconds(10), Title = "Chapter 04" },
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -66,5 +63,4 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(Regex.IsMatch(text0, "metadata_[0-9a-f-]+\\.txt\" -map_metadata 1"), "map_metadata index is calculated incorrectly.");
|
Assert.IsTrue(Regex.IsMatch(text0, "metadata_[0-9a-f-]+\\.txt\" -map_metadata 1"), "map_metadata index is calculated incorrectly.");
|
||||||
Assert.IsTrue(Regex.IsMatch(text1, "metadata_[0-9a-f-]+\\.txt\" -map_metadata 2"), "map_metadata index is calculated incorrectly.");
|
Assert.IsTrue(Regex.IsMatch(text1, "metadata_[0-9a-f-]+\\.txt\" -map_metadata 2"), "map_metadata index is calculated incorrectly.");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class PixelFormatTests
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class PixelFormatTests
|
|
||||||
{
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void PixelFormats_Enumerate()
|
public void PixelFormats_Enumerate()
|
||||||
{
|
{
|
||||||
|
|
@ -37,5 +36,4 @@ namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
Assert.ThrowsExactly<FFMpegException>(() => FFMpeg.GetPixelFormat("yuv420pppUnknown"));
|
Assert.ThrowsExactly<FFMpegException>(() => FFMpeg.GetPixelFormat("yuv420pppUnknown"));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
namespace FFMpegCore.Test.Resources
|
namespace FFMpegCore.Test.Resources;
|
||||||
|
|
||||||
|
public static class TestResources
|
||||||
{
|
{
|
||||||
public static class TestResources
|
|
||||||
{
|
|
||||||
public static readonly string Mp4Video = "./Resources/input_3sec.mp4";
|
public static readonly string Mp4Video = "./Resources/input_3sec.mp4";
|
||||||
public static readonly string Mp4VideoRotation = "./Resources/input_3sec_rotation_90deg.mp4";
|
public static readonly string Mp4VideoRotation = "./Resources/input_3sec_rotation_90deg.mp4";
|
||||||
public static readonly string Mp4VideoRotationNegative = "./Resources/input_3sec_rotation_negative_90deg.mp4";
|
public static readonly string Mp4VideoRotationNegative = "./Resources/input_3sec_rotation_negative_90deg.mp4";
|
||||||
|
|
@ -18,5 +18,4 @@
|
||||||
public static readonly string MkvVideo = "./Resources/sampleMKV.mkv";
|
public static readonly string MkvVideo = "./Resources/sampleMKV.mkv";
|
||||||
public static readonly string Wav24Bit = "./Resources/24_bit_fixed.WAV";
|
public static readonly string Wav24Bit = "./Resources/24_bit_fixed.WAV";
|
||||||
public static readonly string Wav32Bit = "./Resources/32_bit_float.WAV";
|
public static readonly string Wav32Bit = "./Resources/32_bit_float.WAV";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
public class TemporaryFile : IDisposable
|
||||||
{
|
{
|
||||||
public class TemporaryFile : IDisposable
|
|
||||||
{
|
|
||||||
private readonly string _path;
|
private readonly string _path;
|
||||||
|
|
||||||
public TemporaryFile(string filename)
|
public TemporaryFile(string filename)
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
_path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}-{filename}");
|
_path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}-{filename}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static implicit operator string(TemporaryFile temporaryFile) => temporaryFile._path;
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (File.Exists(_path))
|
if (File.Exists(_path))
|
||||||
|
|
@ -17,5 +16,9 @@
|
||||||
File.Delete(_path);
|
File.Delete(_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static implicit operator string(TemporaryFile temporaryFile)
|
||||||
|
{
|
||||||
|
return temporaryFile._path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,14 @@
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
using FFMpegCore.Extensions.System.Drawing.Common;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace FFMpegCore.Test.Utilities
|
namespace FFMpegCore.Test.Utilities;
|
||||||
|
|
||||||
|
internal static class BitmapSource
|
||||||
{
|
{
|
||||||
internal static class BitmapSource
|
|
||||||
{
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
public static IEnumerable<IVideoFrame> CreateBitmaps(int count, PixelFormat fmt, int w, int h)
|
public static IEnumerable<IVideoFrame> CreateBitmaps(int count, PixelFormat fmt, int w, int h)
|
||||||
{
|
{
|
||||||
|
|
@ -33,7 +34,7 @@ namespace FFMpegCore.Test.Utilities
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
public static Extensions.System.Drawing.Common.BitmapVideoFrameWrapper CreateVideoFrame(int index, PixelFormat fmt, int w, int h, float scaleNoise, float offset)
|
public static BitmapVideoFrameWrapper CreateVideoFrame(int index, PixelFormat fmt, int w, int h, float scaleNoise, float offset)
|
||||||
{
|
{
|
||||||
var bitmap = new Bitmap(w, h, fmt);
|
var bitmap = new Bitmap(w, h, fmt);
|
||||||
|
|
||||||
|
|
@ -43,7 +44,7 @@ namespace FFMpegCore.Test.Utilities
|
||||||
bitmap.SetPixel(x, y, color);
|
bitmap.SetPixel(x, y, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Extensions.System.Drawing.Common.BitmapVideoFrameWrapper(bitmap);
|
return new BitmapVideoFrameWrapper(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Extensions.SkiaSharp.BitmapVideoFrameWrapper CreateVideoFrame(int index, SKColorType fmt, int w, int h, float scaleNoise, float offset)
|
public static Extensions.SkiaSharp.BitmapVideoFrameWrapper CreateVideoFrame(int index, SKColorType fmt, int w, int h, float scaleNoise, float offset)
|
||||||
|
|
@ -57,7 +58,8 @@ namespace FFMpegCore.Test.Utilities
|
||||||
return new Extensions.SkiaSharp.BitmapVideoFrameWrapper(bitmap);
|
return new Extensions.SkiaSharp.BitmapVideoFrameWrapper(bitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<(int x, int y, byte red, byte green, byte blue)> GenerateVideoFramePixels(int index, int w, int h, float scaleNoise, float offset)
|
private static IEnumerable<(int x, int y, byte red, byte green, byte blue)> GenerateVideoFramePixels(int index, int w, int h, float scaleNoise,
|
||||||
|
float offset)
|
||||||
{
|
{
|
||||||
offset = offset * index;
|
offset = offset * index;
|
||||||
|
|
||||||
|
|
@ -72,7 +74,7 @@ namespace FFMpegCore.Test.Utilities
|
||||||
|
|
||||||
var value = (byte)((Perlin.Noise(nx, ny) + 1.0f) / 2.0f * 255);
|
var value = (byte)((Perlin.Noise(nx, ny) + 1.0f) / 2.0f * 255);
|
||||||
|
|
||||||
yield return ((x, y, (byte)(value * xf), (byte)(value * yf), value));
|
yield return (x, y, (byte)(value * xf), (byte)(value * yf), value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -228,28 +230,23 @@ namespace FFMpegCore.Test.Utilities
|
||||||
{
|
{
|
||||||
var h = hash & 15;
|
var h = hash & 15;
|
||||||
var u = h < 8 ? x : y;
|
var u = h < 8 ? x : y;
|
||||||
var v = h < 4 ? y : (h == 12 || h == 14 ? x : z);
|
var v = h < 4 ? y : h == 12 || h == 14 ? x : z;
|
||||||
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly int[] perm = {
|
private static readonly int[] perm =
|
||||||
151,160,137,91,90,15,
|
{
|
||||||
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
|
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247,
|
||||||
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
|
120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74,
|
||||||
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
|
165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
|
||||||
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
|
65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3,
|
||||||
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
|
64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183,
|
||||||
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
|
170, 213, 119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178,
|
||||||
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
|
185, 112, 104, 218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214,
|
||||||
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
|
31, 181, 199, 106, 157, 184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195,
|
||||||
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
|
78, 66, 215, 61, 156, 180, 151
|
||||||
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
|
|
||||||
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
|
|
||||||
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
|
|
||||||
151
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test.Utilities;
|
namespace FFMpegCore.Test.Utilities;
|
||||||
|
|
||||||
|
|
@ -15,7 +14,7 @@ public class WindowsOnlyTestMethod : TestMethodAttribute
|
||||||
{
|
{
|
||||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
var message = $"Test not executed on other platforms than Windows";
|
var message = "Test not executed on other platforms than Windows";
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,22 @@ using System.Text;
|
||||||
using FFMpegCore.Arguments;
|
using FFMpegCore.Arguments;
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
using FFMpegCore.Extensions.System.Drawing.Common;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
using FFMpegCore.Test.Resources;
|
using FFMpegCore.Test.Resources;
|
||||||
using FFMpegCore.Test.Utilities;
|
using FFMpegCore.Test.Utilities;
|
||||||
|
using SkiaSharp;
|
||||||
|
using PixelFormat = System.Drawing.Imaging.PixelFormat;
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
[TestClass]
|
||||||
|
public class VideoTest
|
||||||
{
|
{
|
||||||
[TestClass]
|
|
||||||
public class VideoTest
|
|
||||||
{
|
|
||||||
private const int BaseTimeoutMilliseconds = 15_000;
|
private const int BaseTimeoutMilliseconds = 15_000;
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToOGV()
|
public void Video_ToOGV()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Ogv.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Ogv.Extension}");
|
||||||
|
|
@ -28,7 +32,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToMP4()
|
public void Video_ToMP4()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -40,7 +45,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToMP4_YUV444p()
|
public void Video_ToMP4_YUV444p()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -56,7 +62,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("yuv444p", analysis.VideoStreams.First().PixelFormat);
|
Assert.AreEqual("yuv444p", analysis.VideoStreams.First().PixelFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToMP4_Args()
|
public void Video_ToMP4_Args()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -69,10 +76,11 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToH265_MKV_Args()
|
public void Video_ToH265_MKV_Args()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out.mkv");
|
using var outputFile = new TemporaryFile("out.mkv");
|
||||||
|
|
||||||
var success = FFMpegArguments
|
var success = FFMpegArguments
|
||||||
.FromFileInput(TestResources.WebmVideo)
|
.FromFileInput(TestResources.WebmVideo)
|
||||||
|
|
@ -83,15 +91,23 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
[DataRow(System.Drawing.Imaging.PixelFormat.Format24bppRgb)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(System.Drawing.Imaging.PixelFormat.Format32bppArgb)]
|
[DataRow(PixelFormat.Format24bppRgb)]
|
||||||
public void Video_ToMP4_Args_Pipe_WindowsOnly(System.Drawing.Imaging.PixelFormat pixelFormat) => Video_ToMP4_Args_Pipe_Internal(pixelFormat);
|
[DataRow(PixelFormat.Format32bppArgb)]
|
||||||
|
public void Video_ToMP4_Args_Pipe_WindowsOnly(PixelFormat pixelFormat)
|
||||||
|
{
|
||||||
|
Video_ToMP4_Args_Pipe_Internal(pixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
[DataRow(SkiaSharp.SKColorType.Rgb565)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(SkiaSharp.SKColorType.Bgra8888)]
|
[DataRow(SKColorType.Rgb565)]
|
||||||
public void Video_ToMP4_Args_Pipe(SkiaSharp.SKColorType pixelFormat) => Video_ToMP4_Args_Pipe_Internal(pixelFormat);
|
[DataRow(SKColorType.Bgra8888)]
|
||||||
|
public void Video_ToMP4_Args_Pipe(SKColorType pixelFormat)
|
||||||
|
{
|
||||||
|
Video_ToMP4_Args_Pipe_Internal(pixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Video_ToMP4_Args_Pipe_Internal(dynamic pixelFormat)
|
private static void Video_ToMP4_Args_Pipe_Internal(dynamic pixelFormat)
|
||||||
{
|
{
|
||||||
|
|
@ -107,11 +123,19 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
public void Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly() => Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public void Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly()
|
||||||
|
{
|
||||||
|
Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(PixelFormat.Format24bppRgb);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
public void Video_ToMP4_Args_Pipe_DifferentImageSizes() => Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(SkiaSharp.SKColorType.Rgb565);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public void Video_ToMP4_Args_Pipe_DifferentImageSizes()
|
||||||
|
{
|
||||||
|
Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(SKColorType.Rgb565);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(dynamic pixelFormat)
|
private static void Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal(dynamic pixelFormat)
|
||||||
{
|
{
|
||||||
|
|
@ -119,8 +143,7 @@ namespace FFMpegCore.Test
|
||||||
|
|
||||||
var frames = new List<IVideoFrame>
|
var frames = new List<IVideoFrame>
|
||||||
{
|
{
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormat, 255, 255, 1, 0),
|
BitmapSource.CreateVideoFrame(0, pixelFormat, 255, 255, 1, 0), BitmapSource.CreateVideoFrame(0, pixelFormat, 256, 256, 1, 0)
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormat, 256, 256, 1, 0)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var videoFramesSource = new RawVideoPipeSource(frames);
|
var videoFramesSource = new RawVideoPipeSource(frames);
|
||||||
|
|
@ -132,11 +155,19 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly_Async() => await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly_Async()
|
||||||
|
{
|
||||||
|
await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(PixelFormat.Format24bppRgb);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Async() => await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(SkiaSharp.SKColorType.Rgb565);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Async()
|
||||||
|
{
|
||||||
|
await Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(SKColorType.Rgb565);
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(dynamic pixelFormat)
|
private static async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Internal_Async(dynamic pixelFormat)
|
||||||
{
|
{
|
||||||
|
|
@ -144,8 +175,7 @@ namespace FFMpegCore.Test
|
||||||
|
|
||||||
var frames = new List<IVideoFrame>
|
var frames = new List<IVideoFrame>
|
||||||
{
|
{
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormat, 255, 255, 1, 0),
|
BitmapSource.CreateVideoFrame(0, pixelFormat, 255, 255, 1, 0), BitmapSource.CreateVideoFrame(0, pixelFormat, 256, 256, 1, 0)
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormat, 256, 256, 1, 0)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var videoFramesSource = new RawVideoPipeSource(frames);
|
var videoFramesSource = new RawVideoPipeSource(frames);
|
||||||
|
|
@ -157,12 +187,20 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly() =>
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(System.Drawing.Imaging.PixelFormat.Format24bppRgb, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
|
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly()
|
||||||
|
{
|
||||||
|
Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(PixelFormat.Format24bppRgb,
|
||||||
|
PixelFormat.Format32bppRgb);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats() => Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(SkiaSharp.SKColorType.Rgb565, SkiaSharp.SKColorType.Bgra8888);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats()
|
||||||
|
{
|
||||||
|
Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(SKColorType.Rgb565, SKColorType.Bgra8888);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2)
|
private static void Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2)
|
||||||
{
|
{
|
||||||
|
|
@ -170,8 +208,7 @@ namespace FFMpegCore.Test
|
||||||
|
|
||||||
var frames = new List<IVideoFrame>
|
var frames = new List<IVideoFrame>
|
||||||
{
|
{
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormatFrame1, 255, 255, 1, 0),
|
BitmapSource.CreateVideoFrame(0, pixelFormatFrame1, 255, 255, 1, 0), BitmapSource.CreateVideoFrame(0, pixelFormatFrame2, 255, 255, 1, 0)
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormatFrame2, 255, 255, 1, 0)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var videoFramesSource = new RawVideoPipeSource(frames);
|
var videoFramesSource = new RawVideoPipeSource(frames);
|
||||||
|
|
@ -183,12 +220,20 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async() =>
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(System.Drawing.Imaging.PixelFormat.Format24bppRgb, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
|
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async()
|
||||||
|
{
|
||||||
|
await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(PixelFormat.Format24bppRgb,
|
||||||
|
PixelFormat.Format32bppRgb);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Async() => await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(SkiaSharp.SKColorType.Rgb565, SkiaSharp.SKColorType.Bgra8888);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Async()
|
||||||
|
{
|
||||||
|
await Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(SKColorType.Rgb565, SKColorType.Bgra8888);
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2)
|
private static async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Internal_Async(dynamic pixelFormatFrame1, dynamic pixelFormatFrame2)
|
||||||
{
|
{
|
||||||
|
|
@ -196,8 +241,7 @@ namespace FFMpegCore.Test
|
||||||
|
|
||||||
var frames = new List<IVideoFrame>
|
var frames = new List<IVideoFrame>
|
||||||
{
|
{
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormatFrame1, 255, 255, 1, 0),
|
BitmapSource.CreateVideoFrame(0, pixelFormatFrame1, 255, 255, 1, 0), BitmapSource.CreateVideoFrame(0, pixelFormatFrame2, 255, 255, 1, 0)
|
||||||
BitmapSource.CreateVideoFrame(0, pixelFormatFrame2, 255, 255, 1, 0)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var videoFramesSource = new RawVideoPipeSource(frames);
|
var videoFramesSource = new RawVideoPipeSource(frames);
|
||||||
|
|
@ -208,7 +252,8 @@ namespace FFMpegCore.Test
|
||||||
.ProcessAsynchronously());
|
.ProcessAsynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToMP4_Args_StreamPipe()
|
public void Video_ToMP4_Args_StreamPipe()
|
||||||
{
|
{
|
||||||
using var input = File.OpenRead(TestResources.WebmVideo);
|
using var input = File.OpenRead(TestResources.WebmVideo);
|
||||||
|
|
@ -222,7 +267,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure()
|
public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure()
|
||||||
{
|
{
|
||||||
await Assert.ThrowsExactlyAsync<FFMpegException>(async () =>
|
await Assert.ThrowsExactlyAsync<FFMpegException>(async () =>
|
||||||
|
|
@ -236,7 +282,8 @@ namespace FFMpegCore.Test
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_StreamFile_OutputToMemoryStream()
|
public void Video_StreamFile_OutputToMemoryStream()
|
||||||
{
|
{
|
||||||
var output = new MemoryStream();
|
var output = new MemoryStream();
|
||||||
|
|
@ -253,7 +300,8 @@ namespace FFMpegCore.Test
|
||||||
Console.WriteLine(result.Duration);
|
Console.WriteLine(result.Duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToMP4_Args_StreamOutputPipe_Failure()
|
public void Video_ToMP4_Args_StreamOutputPipe_Failure()
|
||||||
{
|
{
|
||||||
Assert.ThrowsExactly<FFMpegException>(() =>
|
Assert.ThrowsExactly<FFMpegException>(() =>
|
||||||
|
|
@ -267,7 +315,8 @@ namespace FFMpegCore.Test
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_ToMP4_Args_StreamOutputPipe_Async()
|
public async Task Video_ToMP4_Args_StreamOutputPipe_Async()
|
||||||
{
|
{
|
||||||
await using var ms = new MemoryStream();
|
await using var ms = new MemoryStream();
|
||||||
|
|
@ -280,7 +329,8 @@ namespace FFMpegCore.Test
|
||||||
.ProcessAsynchronously();
|
.ProcessAsynchronously();
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task TestDuplicateRun()
|
public async Task TestDuplicateRun()
|
||||||
{
|
{
|
||||||
FFMpegArguments
|
FFMpegArguments
|
||||||
|
|
@ -296,7 +346,8 @@ namespace FFMpegCore.Test
|
||||||
File.Delete("temporary.mp4");
|
File.Delete("temporary.mp4");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void TranscodeToMemoryStream_Success()
|
public void TranscodeToMemoryStream_Success()
|
||||||
{
|
{
|
||||||
using var output = new MemoryStream();
|
using var output = new MemoryStream();
|
||||||
|
|
@ -314,7 +365,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(inputAnalysis.Duration.TotalSeconds, outputAnalysis.Duration.TotalSeconds, 0.3);
|
Assert.AreEqual(inputAnalysis.Duration.TotalSeconds, outputAnalysis.Duration.TotalSeconds, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToTS()
|
public void Video_ToTS()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.MpegTs.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.MpegTs.Extension}");
|
||||||
|
|
@ -326,7 +378,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToTS_Args()
|
public void Video_ToTS_Args()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.MpegTs.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.MpegTs.Extension}");
|
||||||
|
|
@ -342,15 +395,23 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
[DataRow(System.Drawing.Imaging.PixelFormat.Format24bppRgb)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(System.Drawing.Imaging.PixelFormat.Format32bppArgb)]
|
[DataRow(PixelFormat.Format24bppRgb)]
|
||||||
public async Task Video_ToTS_Args_Pipe_WindowsOnly(System.Drawing.Imaging.PixelFormat pixelFormat) => await Video_ToTS_Args_Pipe_Internal(pixelFormat);
|
[DataRow(PixelFormat.Format32bppArgb)]
|
||||||
|
public async Task Video_ToTS_Args_Pipe_WindowsOnly(PixelFormat pixelFormat)
|
||||||
|
{
|
||||||
|
await Video_ToTS_Args_Pipe_Internal(pixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
[DataRow(SkiaSharp.SKColorType.Rgb565)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(SkiaSharp.SKColorType.Bgra8888)]
|
[DataRow(SKColorType.Rgb565)]
|
||||||
public async Task Video_ToTS_Args_Pipe(SkiaSharp.SKColorType pixelFormat) => await Video_ToTS_Args_Pipe_Internal(pixelFormat);
|
[DataRow(SKColorType.Bgra8888)]
|
||||||
|
public async Task Video_ToTS_Args_Pipe(SKColorType pixelFormat)
|
||||||
|
{
|
||||||
|
await Video_ToTS_Args_Pipe_Internal(pixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
private static async Task Video_ToTS_Args_Pipe_Internal(dynamic pixelFormat)
|
private static async Task Video_ToTS_Args_Pipe_Internal(dynamic pixelFormat)
|
||||||
{
|
{
|
||||||
|
|
@ -368,7 +429,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(VideoType.Ts.Name, analysis.Format.FormatName);
|
Assert.AreEqual(VideoType.Ts.Name, analysis.Format.FormatName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_ToOGV_Resize()
|
public async Task Video_ToOGV_Resize()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Ogv.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Ogv.Extension}");
|
||||||
|
|
@ -382,10 +444,11 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
[DataRow(SkiaSharp.SKColorType.Rgb565)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(SkiaSharp.SKColorType.Bgra8888)]
|
[DataRow(SKColorType.Rgb565)]
|
||||||
public void RawVideoPipeSource_Ogv_Scale(SkiaSharp.SKColorType pixelFormat)
|
[DataRow(SKColorType.Bgra8888)]
|
||||||
|
public void RawVideoPipeSource_Ogv_Scale(SKColorType pixelFormat)
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Ogv.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Ogv.Extension}");
|
||||||
var videoFramesSource = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256));
|
var videoFramesSource = new RawVideoPipeSource(BitmapSource.CreateBitmaps(128, pixelFormat, 256, 256));
|
||||||
|
|
@ -402,7 +465,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual((int)VideoSize.Ed, analysis.PrimaryVideoStream!.Width);
|
Assert.AreEqual((int)VideoSize.Ed, analysis.PrimaryVideoStream!.Width);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Scale_Mp4_Multithreaded()
|
public void Scale_Mp4_Multithreaded()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
|
||||||
|
|
@ -417,16 +481,24 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
[DataRow(System.Drawing.Imaging.PixelFormat.Format24bppRgb)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(System.Drawing.Imaging.PixelFormat.Format32bppArgb)]
|
[DataRow(PixelFormat.Format24bppRgb)]
|
||||||
|
[DataRow(PixelFormat.Format32bppArgb)]
|
||||||
// [DataRow(PixelFormat.Format48bppRgb)]
|
// [DataRow(PixelFormat.Format48bppRgb)]
|
||||||
public void Video_ToMP4_Resize_Args_Pipe(System.Drawing.Imaging.PixelFormat pixelFormat) => Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat);
|
public void Video_ToMP4_Resize_Args_Pipe(PixelFormat pixelFormat)
|
||||||
|
{
|
||||||
|
Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
[DataRow(SkiaSharp.SKColorType.Rgb565)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(SkiaSharp.SKColorType.Bgra8888)]
|
[DataRow(SKColorType.Rgb565)]
|
||||||
public void Video_ToMP4_Resize_Args_Pipe(SkiaSharp.SKColorType pixelFormat) => Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat);
|
[DataRow(SKColorType.Bgra8888)]
|
||||||
|
public void Video_ToMP4_Resize_Args_Pipe(SKColorType pixelFormat)
|
||||||
|
{
|
||||||
|
Video_ToMP4_Resize_Args_Pipe_Internal(pixelFormat);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Video_ToMP4_Resize_Args_Pipe_Internal(dynamic pixelFormat)
|
private static void Video_ToMP4_Resize_Args_Pipe_Internal(dynamic pixelFormat)
|
||||||
{
|
{
|
||||||
|
|
@ -442,10 +514,11 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_InMemory_SystemDrawingCommon()
|
public void Video_Snapshot_InMemory_SystemDrawingCommon()
|
||||||
{
|
{
|
||||||
using var bitmap = Extensions.System.Drawing.Common.FFMpegImage.Snapshot(TestResources.Mp4Video);
|
using var bitmap = FFMpegImage.Snapshot(TestResources.Mp4Video);
|
||||||
|
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
Assert.AreEqual(input.PrimaryVideoStream!.Width, bitmap.Width);
|
Assert.AreEqual(input.PrimaryVideoStream!.Width, bitmap.Width);
|
||||||
|
|
@ -453,7 +526,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(bitmap.RawFormat, ImageFormat.Png);
|
Assert.AreEqual(bitmap.RawFormat, ImageFormat.Png);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_InMemory_SkiaSharp()
|
public void Video_Snapshot_InMemory_SkiaSharp()
|
||||||
{
|
{
|
||||||
using var bitmap = Extensions.SkiaSharp.FFMpegImage.Snapshot(TestResources.Mp4Video);
|
using var bitmap = Extensions.SkiaSharp.FFMpegImage.Snapshot(TestResources.Mp4Video);
|
||||||
|
|
@ -465,7 +539,8 @@ namespace FFMpegCore.Test
|
||||||
// e.g. Bgra8888 on Windows and Rgba8888 on macOS.
|
// e.g. Bgra8888 on Windows and Rgba8888 on macOS.
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_Png_PersistSnapshot()
|
public void Video_Snapshot_Png_PersistSnapshot()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.png");
|
using var outputPath = new TemporaryFile("out.png");
|
||||||
|
|
@ -479,7 +554,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("png", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("png", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_Jpg_PersistSnapshot()
|
public void Video_Snapshot_Jpg_PersistSnapshot()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.jpg");
|
using var outputPath = new TemporaryFile("out.jpg");
|
||||||
|
|
@ -493,7 +569,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("mjpeg", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("mjpeg", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_Bmp_PersistSnapshot()
|
public void Video_Snapshot_Bmp_PersistSnapshot()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.bmp");
|
using var outputPath = new TemporaryFile("out.bmp");
|
||||||
|
|
@ -507,7 +584,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("bmp", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("bmp", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_Webp_PersistSnapshot()
|
public void Video_Snapshot_Webp_PersistSnapshot()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.webp");
|
using var outputPath = new TemporaryFile("out.webp");
|
||||||
|
|
@ -521,7 +599,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("webp", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("webp", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_Exception_PersistSnapshot()
|
public void Video_Snapshot_Exception_PersistSnapshot()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.asd");
|
using var outputPath = new TemporaryFile("out.asd");
|
||||||
|
|
@ -536,7 +615,8 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_Rotated_PersistSnapshot()
|
public void Video_Snapshot_Rotated_PersistSnapshot()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.png");
|
using var outputPath = new TemporaryFile("out.png");
|
||||||
|
|
@ -551,7 +631,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("png", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("png", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_GifSnapshot_PersistSnapshot()
|
public void Video_GifSnapshot_PersistSnapshot()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.gif");
|
using var outputPath = new TemporaryFile("out.gif");
|
||||||
|
|
@ -565,14 +646,15 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_GifSnapshot_PersistSnapshot_SizeSupplied()
|
public void Video_GifSnapshot_PersistSnapshot_SizeSupplied()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.gif");
|
using var outputPath = new TemporaryFile("out.gif");
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
var desiredGifSize = new Size(320, 240);
|
var desiredGifSize = new Size(320, 240);
|
||||||
|
|
||||||
FFMpeg.GifSnapshot(TestResources.Mp4Video, outputPath, desiredGifSize, captureTime: TimeSpan.FromSeconds(0));
|
FFMpeg.GifSnapshot(TestResources.Mp4Video, outputPath, desiredGifSize, TimeSpan.FromSeconds(0));
|
||||||
|
|
||||||
var analysis = FFProbe.Analyse(outputPath);
|
var analysis = FFProbe.Analyse(outputPath);
|
||||||
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, desiredGifSize.Width);
|
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, desiredGifSize.Width);
|
||||||
|
|
@ -580,7 +662,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_GifSnapshot_PersistSnapshotAsync()
|
public async Task Video_GifSnapshot_PersistSnapshotAsync()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.gif");
|
using var outputPath = new TemporaryFile("out.gif");
|
||||||
|
|
@ -594,14 +677,15 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_GifSnapshot_PersistSnapshotAsync_SizeSupplied()
|
public async Task Video_GifSnapshot_PersistSnapshotAsync_SizeSupplied()
|
||||||
{
|
{
|
||||||
using var outputPath = new TemporaryFile("out.gif");
|
using var outputPath = new TemporaryFile("out.gif");
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
var desiredGifSize = new Size(320, 240);
|
var desiredGifSize = new Size(320, 240);
|
||||||
|
|
||||||
await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, desiredGifSize, captureTime: TimeSpan.FromSeconds(0));
|
await FFMpeg.GifSnapshotAsync(TestResources.Mp4Video, outputPath, desiredGifSize, TimeSpan.FromSeconds(0));
|
||||||
|
|
||||||
var analysis = FFProbe.Analyse(outputPath);
|
var analysis = FFProbe.Analyse(outputPath);
|
||||||
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, desiredGifSize.Width);
|
Assert.AreNotEqual(input.PrimaryVideoStream!.Width, desiredGifSize.Width);
|
||||||
|
|
@ -609,7 +693,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
Assert.AreEqual("gif", analysis.PrimaryVideoStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Join()
|
public void Video_Join()
|
||||||
{
|
{
|
||||||
using var inputCopy = new TemporaryFile("copy-input.mp4");
|
using var inputCopy = new TemporaryFile("copy-input.mp4");
|
||||||
|
|
@ -631,7 +716,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(input.PrimaryVideoStream.Width, result.PrimaryVideoStream.Width);
|
Assert.AreEqual(input.PrimaryVideoStream.Width, result.PrimaryVideoStream.Width);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(2 * BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(2 * BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Join_Image_Sequence()
|
public void Video_Join_Image_Sequence()
|
||||||
{
|
{
|
||||||
var imageSet = new List<string>();
|
var imageSet = new List<string>();
|
||||||
|
|
@ -647,7 +733,7 @@ namespace FFMpegCore.Test
|
||||||
var imageAnalysis = FFProbe.Analyse(imageSet.First());
|
var imageAnalysis = FFProbe.Analyse(imageSet.First());
|
||||||
|
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
var success = FFMpeg.JoinImageSequence(outputFile, frameRate: 10, images: imageSet.ToArray());
|
var success = FFMpeg.JoinImageSequence(outputFile, 10, imageSet.ToArray());
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
var result = FFProbe.Analyse(outputFile);
|
var result = FFProbe.Analyse(outputFile);
|
||||||
|
|
||||||
|
|
@ -656,7 +742,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(imageAnalysis.PrimaryVideoStream!.Height, result.PrimaryVideoStream.Height);
|
Assert.AreEqual(imageAnalysis.PrimaryVideoStream!.Height, result.PrimaryVideoStream.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_With_Only_Audio_Should_Extract_Metadata()
|
public void Video_With_Only_Audio_Should_Extract_Metadata()
|
||||||
{
|
{
|
||||||
var video = FFProbe.Analyse(TestResources.Mp4WithoutVideo);
|
var video = FFProbe.Analyse(TestResources.Mp4WithoutVideo);
|
||||||
|
|
@ -665,7 +752,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(10, video.Duration.TotalSeconds, 0.5);
|
Assert.AreEqual(10, video.Duration.TotalSeconds, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Duration()
|
public void Video_Duration()
|
||||||
{
|
{
|
||||||
var video = FFProbe.Analyse(TestResources.Mp4Video);
|
var video = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
|
|
@ -685,7 +773,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(video.Duration.Seconds - 2, outputVideo.Duration.Seconds);
|
Assert.AreEqual(video.Duration.Seconds - 2, outputVideo.Duration.Seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_UpdatesProgress()
|
public void Video_UpdatesProgress()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -726,7 +815,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreNotEqual(analysis.Duration, timeDone);
|
Assert.AreNotEqual(analysis.Duration, timeDone);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_OutputsData()
|
public void Video_OutputsData()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -748,11 +838,19 @@ namespace FFMpegCore.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[WindowsOnlyTestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[WindowsOnlyTestMethod]
|
||||||
public void Video_TranscodeInMemory_WindowsOnly() => Video_TranscodeInMemory_Internal(System.Drawing.Imaging.PixelFormat.Format24bppRgb);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public void Video_TranscodeInMemory_WindowsOnly()
|
||||||
|
{
|
||||||
|
Video_TranscodeInMemory_Internal(PixelFormat.Format24bppRgb);
|
||||||
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
public void Video_TranscodeInMemory() => Video_TranscodeInMemory_Internal(SkiaSharp.SKColorType.Rgb565);
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
|
public void Video_TranscodeInMemory()
|
||||||
|
{
|
||||||
|
Video_TranscodeInMemory_Internal(SKColorType.Rgb565);
|
||||||
|
}
|
||||||
|
|
||||||
private static void Video_TranscodeInMemory_Internal(dynamic pixelFormat)
|
private static void Video_TranscodeInMemory_Internal(dynamic pixelFormat)
|
||||||
{
|
{
|
||||||
|
|
@ -773,7 +871,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(128, vi.PrimaryVideoStream.Height);
|
Assert.AreEqual(128, vi.PrimaryVideoStream.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(2 * BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(2 * BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_TranscodeToMemory()
|
public void Video_TranscodeToMemory()
|
||||||
{
|
{
|
||||||
using var memoryStream = new MemoryStream();
|
using var memoryStream = new MemoryStream();
|
||||||
|
|
@ -791,7 +890,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual(360, vi.PrimaryVideoStream.Height);
|
Assert.AreEqual(360, vi.PrimaryVideoStream.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_Cancel_Async()
|
public async Task Video_Cancel_Async()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -815,7 +915,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsFalse(result);
|
Assert.IsFalse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Cancel()
|
public void Video_Cancel()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -829,14 +930,15 @@ namespace FFMpegCore.Test
|
||||||
.WithSpeedPreset(Speed.VeryFast))
|
.WithSpeedPreset(Speed.VeryFast))
|
||||||
.CancellableThrough(out var cancel);
|
.CancellableThrough(out var cancel);
|
||||||
|
|
||||||
Task.Delay(300).ContinueWith((_) => cancel());
|
Task.Delay(300).ContinueWith(_ => cancel());
|
||||||
|
|
||||||
var result = task.ProcessSynchronously(false);
|
var result = task.ProcessSynchronously(false);
|
||||||
|
|
||||||
Assert.IsFalse(result);
|
Assert.IsFalse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_Cancel_Async_With_Timeout()
|
public async Task Video_Cancel_Async_With_Timeout()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -866,7 +968,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("aac", outputInfo.PrimaryAudioStream!.CodecName);
|
Assert.AreEqual("aac", outputInfo.PrimaryAudioStream!.CodecName);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_Cancel_CancellationToken_Async()
|
public async Task Video_Cancel_CancellationToken_Async()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -891,7 +994,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.IsFalse(result);
|
Assert.IsFalse(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_Cancel_CancellationToken_Async_Throws()
|
public async Task Video_Cancel_CancellationToken_Async_Throws()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -914,7 +1018,8 @@ namespace FFMpegCore.Test
|
||||||
await Assert.ThrowsExactlyAsync<OperationCanceledException>(() => task);
|
await Assert.ThrowsExactlyAsync<OperationCanceledException>(() => task);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Cancel_CancellationToken_Throws()
|
public void Video_Cancel_CancellationToken_Throws()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -936,7 +1041,8 @@ namespace FFMpegCore.Test
|
||||||
Assert.ThrowsExactly<OperationCanceledException>(() => task.ProcessSynchronously());
|
Assert.ThrowsExactly<OperationCanceledException>(() => task.ProcessSynchronously());
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[TestMethod]
|
||||||
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_Cancel_CancellationToken_Async_With_Timeout()
|
public async Task Video_Cancel_CancellationToken_Async_With_Timeout()
|
||||||
{
|
{
|
||||||
using var outputFile = new TemporaryFile("out.mp4");
|
using var outputFile = new TemporaryFile("out.mp4");
|
||||||
|
|
@ -966,5 +1072,4 @@ namespace FFMpegCore.Test
|
||||||
Assert.AreEqual("h264", outputInfo.PrimaryVideoStream.CodecName);
|
Assert.AreEqual("h264", outputInfo.PrimaryVideoStream.CodecName);
|
||||||
Assert.AreEqual("aac", outputInfo.PrimaryAudioStream!.CodecName);
|
Assert.AreEqual("aac", outputInfo.PrimaryAudioStream!.CodecName);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
namespace FFMpegCore.Extend
|
namespace FFMpegCore.Extend;
|
||||||
|
|
||||||
|
internal static class KeyValuePairExtensions
|
||||||
{
|
{
|
||||||
internal static class KeyValuePairExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Concat the two members of a <see cref="KeyValuePair{TKey,TValue}" />
|
/// Concat the two members of a <see cref="KeyValuePair{TKey,TValue}" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -18,5 +18,4 @@
|
||||||
|
|
||||||
return $"{key}={value}";
|
return $"{key}={value}";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
|
|
||||||
namespace FFMpegCore.Extend
|
namespace FFMpegCore.Extend;
|
||||||
|
|
||||||
|
public class PcmAudioSampleWrapper : IAudioSample
|
||||||
{
|
{
|
||||||
public class PcmAudioSampleWrapper : IAudioSample
|
|
||||||
{
|
|
||||||
//This could actually be short or int, but copies would be inefficient.
|
//This could actually be short or int, but copies would be inefficient.
|
||||||
//Handling bytes lets the user decide on the conversion, and abstract the library
|
//Handling bytes lets the user decide on the conversion, and abstract the library
|
||||||
//from handling shorts, unsigned shorts, integers, unsigned integers and floats.
|
//from handling shorts, unsigned shorts, integers, unsigned integers and floats.
|
||||||
|
|
@ -23,5 +23,4 @@ namespace FFMpegCore.Extend
|
||||||
{
|
{
|
||||||
await stream.WriteAsync(_sample, 0, _sample.Length, token).ConfigureAwait(false);
|
await stream.WriteAsync(_sample, 0, _sample.Length, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace FFMpegCore.Extend
|
namespace FFMpegCore.Extend;
|
||||||
|
|
||||||
|
internal static class StringExtensions
|
||||||
{
|
{
|
||||||
internal static class StringExtensions
|
|
||||||
{
|
|
||||||
private static Dictionary<char, string> CharactersSubstitution { get; } = new()
|
private static Dictionary<char, string> CharactersSubstitution { get; } = new()
|
||||||
{
|
{
|
||||||
{ '\\', @"\\" },
|
{ '\\', @"\\" },
|
||||||
|
|
@ -65,5 +65,4 @@ namespace FFMpegCore.Extend
|
||||||
|
|
||||||
return parsedString.ToString();
|
return parsedString.ToString();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
namespace FFMpegCore.Extend
|
namespace FFMpegCore.Extend;
|
||||||
|
|
||||||
|
public static class UriExtensions
|
||||||
{
|
{
|
||||||
public static class UriExtensions
|
|
||||||
{
|
|
||||||
public static bool SaveStream(this Uri uri, string output)
|
public static bool SaveStream(this Uri uri, string output)
|
||||||
{
|
{
|
||||||
return FFMpeg.SaveM3U8Stream(uri, output);
|
return FFMpeg.SaveM3U8Stream(uri, output);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class AudibleEncryptionKeyArgument : IArgument
|
||||||
{
|
{
|
||||||
public class AudibleEncryptionKeyArgument : IArgument
|
|
||||||
{
|
|
||||||
private readonly bool _aaxcMode;
|
private readonly bool _aaxcMode;
|
||||||
|
|
||||||
private readonly string? _key;
|
private readonly string? _activationBytes;
|
||||||
private readonly string? _iv;
|
private readonly string? _iv;
|
||||||
|
|
||||||
private readonly string? _activationBytes;
|
private readonly string? _key;
|
||||||
|
|
||||||
public AudibleEncryptionKeyArgument(string activationBytes)
|
public AudibleEncryptionKeyArgument(string activationBytes)
|
||||||
{
|
{
|
||||||
|
|
@ -23,5 +23,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => _aaxcMode ? $"-audible_key {_key} -audible_iv {_iv}" : $"-activation_bytes {_activationBytes}";
|
public string Text => _aaxcMode ? $"-audible_key {_key} -audible_iv {_iv}" : $"-activation_bytes {_activationBytes}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents parameter of audio codec and it's quality
|
||||||
|
/// </summary>
|
||||||
|
public class AudioBitrateArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents parameter of audio codec and it's quality
|
|
||||||
/// </summary>
|
|
||||||
public class AudioBitrateArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int Bitrate;
|
public readonly int Bitrate;
|
||||||
public AudioBitrateArgument(AudioQuality value) : this((int)value) { }
|
public AudioBitrateArgument(AudioQuality value) : this((int)value) { }
|
||||||
|
|
||||||
public AudioBitrateArgument(int bitrate)
|
public AudioBitrateArgument(int bitrate)
|
||||||
{
|
{
|
||||||
Bitrate = bitrate;
|
Bitrate = bitrate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-b:a {Bitrate}k";
|
public string Text => $"-b:a {Bitrate}k";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents parameter of audio codec and it's quality
|
||||||
|
/// </summary>
|
||||||
|
public class AudioCodecArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents parameter of audio codec and it's quality
|
|
||||||
/// </summary>
|
|
||||||
public class AudioCodecArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly string AudioCodec;
|
public readonly string AudioCodec;
|
||||||
|
|
||||||
public AudioCodecArgument(Codec audioCodec)
|
public AudioCodecArgument(Codec audioCodec)
|
||||||
|
|
@ -25,6 +25,5 @@ namespace FFMpegCore.Arguments
|
||||||
AudioCodec = audioCodec;
|
AudioCodec = audioCodec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-c:a {AudioCodec.ToString().ToLowerInvariant()}";
|
public string Text => $"-c:a {AudioCodec.ToLowerInvariant()}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class AudioFiltersArgument : IArgument
|
||||||
{
|
{
|
||||||
public class AudioFiltersArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly AudioFilterOptions Options;
|
public readonly AudioFilterOptions Options;
|
||||||
|
|
||||||
public AudioFiltersArgument(AudioFilterOptions options)
|
public AudioFiltersArgument(AudioFilterOptions options)
|
||||||
|
|
@ -30,42 +30,68 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
return $"-af \"{string.Join(", ", arguments)}\"";
|
return $"-af \"{string.Join(", ", arguments)}\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IAudioFilterArgument
|
public interface IAudioFilterArgument
|
||||||
{
|
{
|
||||||
string Key { get; }
|
string Key { get; }
|
||||||
string Value { get; }
|
string Value { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AudioFilterOptions
|
public class AudioFilterOptions
|
||||||
{
|
{
|
||||||
public List<IAudioFilterArgument> Arguments { get; } = new();
|
public List<IAudioFilterArgument> Arguments { get; } = new();
|
||||||
|
|
||||||
public AudioFilterOptions Pan(string channelLayout, params string[] outputDefinitions) => WithArgument(new PanArgument(channelLayout, outputDefinitions));
|
public AudioFilterOptions Pan(string channelLayout, params string[] outputDefinitions)
|
||||||
public AudioFilterOptions Pan(int channels, params string[] outputDefinitions) => WithArgument(new PanArgument(channels, outputDefinitions));
|
{
|
||||||
|
return WithArgument(new PanArgument(channelLayout, outputDefinitions));
|
||||||
|
}
|
||||||
|
|
||||||
|
public AudioFilterOptions Pan(int channels, params string[] outputDefinitions)
|
||||||
|
{
|
||||||
|
return WithArgument(new PanArgument(channels, outputDefinitions));
|
||||||
|
}
|
||||||
|
|
||||||
public AudioFilterOptions DynamicNormalizer(int frameLength = 500, int filterWindow = 31, double targetPeak = 0.95,
|
public AudioFilterOptions DynamicNormalizer(int frameLength = 500, int filterWindow = 31, double targetPeak = 0.95,
|
||||||
double gainFactor = 10.0, double targetRms = 0.0, bool channelCoupling = true,
|
double gainFactor = 10.0, double targetRms = 0.0, bool channelCoupling = true,
|
||||||
bool enableDcBiasCorrection = false, bool enableAlternativeBoundary = false,
|
bool enableDcBiasCorrection = false, bool enableAlternativeBoundary = false,
|
||||||
double compressorFactor = 0.0) => WithArgument(new DynamicNormalizerArgument(frameLength, filterWindow,
|
double compressorFactor = 0.0)
|
||||||
|
{
|
||||||
|
return WithArgument(new DynamicNormalizerArgument(frameLength, filterWindow,
|
||||||
targetPeak, gainFactor, targetRms, channelCoupling, enableDcBiasCorrection, enableAlternativeBoundary,
|
targetPeak, gainFactor, targetRms, channelCoupling, enableDcBiasCorrection, enableAlternativeBoundary,
|
||||||
compressorFactor));
|
compressorFactor));
|
||||||
|
}
|
||||||
|
|
||||||
public AudioFilterOptions HighPass(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707,
|
public AudioFilterOptions HighPass(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707,
|
||||||
double mix = 1, string channels = "", bool normalize = false, string transform = "", string precision = "auto",
|
double mix = 1, string channels = "", bool normalize = false, string transform = "", string precision = "auto",
|
||||||
int? blocksize = null) => WithArgument(new HighPassFilterArgument(frequency, poles, width_type, width, mix, channels, normalize, transform, precision, blocksize));
|
int? blocksize = null)
|
||||||
|
{
|
||||||
|
return WithArgument(new HighPassFilterArgument(frequency, poles, width_type, width, mix, channels, normalize, transform, precision, blocksize));
|
||||||
|
}
|
||||||
|
|
||||||
public AudioFilterOptions LowPass(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707,
|
public AudioFilterOptions LowPass(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707,
|
||||||
double mix = 1, string channels = "", bool normalize = false, string transform = "", string precision = "auto",
|
double mix = 1, string channels = "", bool normalize = false, string transform = "", string precision = "auto",
|
||||||
int? blocksize = null) => WithArgument(new LowPassFilterArgument(frequency, poles, width_type, width, mix, channels, normalize, transform, precision, blocksize));
|
int? blocksize = null)
|
||||||
|
{
|
||||||
|
return WithArgument(new LowPassFilterArgument(frequency, poles, width_type, width, mix, channels, normalize, transform, precision, blocksize));
|
||||||
|
}
|
||||||
|
|
||||||
public AudioFilterOptions AudioGate(double level_in = 1, string mode = "downward", double range = 0.06125, double threshold = 0.125,
|
public AudioFilterOptions AudioGate(double level_in = 1, string mode = "downward", double range = 0.06125, double threshold = 0.125,
|
||||||
int ratio = 2, double attack = 20, double release = 250, int makeup = 1, double knee = 2.828427125, string detection = "rms",
|
int ratio = 2, double attack = 20, double release = 250, int makeup = 1, double knee = 2.828427125, string detection = "rms",
|
||||||
string link = "average") => WithArgument(new AudioGateArgument(level_in, mode, range, threshold, ratio, attack, release, makeup, knee, detection, link));
|
string link = "average")
|
||||||
|
{
|
||||||
|
return WithArgument(new AudioGateArgument(level_in, mode, range, threshold, ratio, attack, release, makeup, knee, detection, link));
|
||||||
|
}
|
||||||
|
|
||||||
public AudioFilterOptions SilenceDetect(string noise_type = "db", double noise = 60, double duration = 2,
|
public AudioFilterOptions SilenceDetect(string noise_type = "db", double noise = 60, double duration = 2,
|
||||||
bool mono = false) => WithArgument(new SilenceDetectArgument(noise_type, noise, duration, mono));
|
bool mono = false)
|
||||||
|
{
|
||||||
|
return WithArgument(new SilenceDetectArgument(noise_type, noise, duration, mono));
|
||||||
|
}
|
||||||
|
|
||||||
private AudioFilterOptions WithArgument(IAudioFilterArgument argument)
|
private AudioFilterOptions WithArgument(IAudioFilterArgument argument)
|
||||||
{
|
{
|
||||||
Arguments.Add(argument);
|
Arguments.Add(argument);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,43 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class AudioGateArgument : IAudioFilterArgument
|
||||||
{
|
{
|
||||||
public class AudioGateArgument : IAudioFilterArgument
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, string> _arguments = new();
|
private readonly Dictionary<string, string> _arguments = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Audio Gate. <see href="https://ffmpeg.org/ffmpeg-filters.html#agate"/>
|
/// Audio Gate. <see href="https://ffmpeg.org/ffmpeg-filters.html#agate" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="levelIn">Set input level before filtering. Default is 1. Allowed range is from 0.015625 to 64.</param>
|
/// <param name="levelIn">Set input level before filtering. Default is 1. Allowed range is from 0.015625 to 64.</param>
|
||||||
/// <param name="mode">Set the mode of operation. Can be upward or downward. Default is downward. If set to upward mode, higher parts of signal will be amplified, expanding dynamic range in upward direction. Otherwise, in case of downward lower parts of signal will be reduced.</param>
|
/// <param name="mode">
|
||||||
/// <param name="range">Set the level of gain reduction when the signal is below the threshold. Default is 0.06125. Allowed range is from 0 to 1. Setting this to 0 disables reduction and then filter behaves like expander.</param>
|
/// Set the mode of operation. Can be upward or downward. Default is downward. If set to upward mode, higher parts of signal
|
||||||
|
/// will be amplified, expanding dynamic range in upward direction. Otherwise, in case of downward lower parts of signal will be reduced.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="range">
|
||||||
|
/// Set the level of gain reduction when the signal is below the threshold. Default is 0.06125. Allowed range is from 0 to
|
||||||
|
/// 1. Setting this to 0 disables reduction and then filter behaves like expander.
|
||||||
|
/// </param>
|
||||||
/// <param name="threshold">If a signal rises above this level the gain reduction is released. Default is 0.125. Allowed range is from 0 to 1.</param>
|
/// <param name="threshold">If a signal rises above this level the gain reduction is released. Default is 0.125. Allowed range is from 0 to 1.</param>
|
||||||
/// <param name="ratio">Set a ratio by which the signal is reduced. Default is 2. Allowed range is from 1 to 9000.</param>
|
/// <param name="ratio">Set a ratio by which the signal is reduced. Default is 2. Allowed range is from 1 to 9000.</param>
|
||||||
/// <param name="attack">Amount of milliseconds the signal has to rise above the threshold before gain reduction stops. Default is 20 milliseconds. Allowed range is from 0.01 to 9000.</param>
|
/// <param name="attack">
|
||||||
/// <param name="release">Amount of milliseconds the signal has to fall below the threshold before the reduction is increased again. Default is 250 milliseconds. Allowed range is from 0.01 to 9000.</param>
|
/// Amount of milliseconds the signal has to rise above the threshold before gain reduction stops. Default is 20
|
||||||
|
/// milliseconds. Allowed range is from 0.01 to 9000.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="release">
|
||||||
|
/// Amount of milliseconds the signal has to fall below the threshold before the reduction is increased again. Default is
|
||||||
|
/// 250 milliseconds. Allowed range is from 0.01 to 9000.
|
||||||
|
/// </param>
|
||||||
/// <param name="makeup">Set amount of amplification of signal after processing. Default is 1. Allowed range is from 1 to 64.</param>
|
/// <param name="makeup">Set amount of amplification of signal after processing. Default is 1. Allowed range is from 1 to 64.</param>
|
||||||
/// <param name="knee">Curve the sharp knee around the threshold to enter gain reduction more softly. Default is 2.828427125. Allowed range is from 1 to 8.</param>
|
/// <param name="knee">
|
||||||
|
/// Curve the sharp knee around the threshold to enter gain reduction more softly. Default is 2.828427125. Allowed range is
|
||||||
|
/// from 1 to 8.
|
||||||
|
/// </param>
|
||||||
/// <param name="detection">Choose if exact signal should be taken for detection or an RMS like one. Default is rms. Can be peak or rms.</param>
|
/// <param name="detection">Choose if exact signal should be taken for detection or an RMS like one. Default is rms. Can be peak or rms.</param>
|
||||||
/// <param name="link">Choose if the average level between all channels or the louder channel affects the reduction. Default is average. Can be average or maximum.</param>
|
/// <param name="link">
|
||||||
|
/// Choose if the average level between all channels or the louder channel affects the reduction. Default is average. Can be
|
||||||
|
/// average or maximum.
|
||||||
|
/// </param>
|
||||||
public AudioGateArgument(double levelIn = 1, string mode = "downward", double range = 0.06125, double threshold = 0.125, int ratio = 2,
|
public AudioGateArgument(double levelIn = 1, string mode = "downward", double range = 0.06125, double threshold = 0.125, int ratio = 2,
|
||||||
double attack = 20, double release = 250, int makeup = 1, double knee = 2.828427125, string detection = "rms", string link = "average")
|
double attack = 20, double release = 250, int makeup = 1, double knee = 2.828427125, string detection = "rms", string link = "average")
|
||||||
{
|
{
|
||||||
|
|
@ -94,5 +112,4 @@ namespace FFMpegCore.Arguments
|
||||||
public string Key { get; } = "agate";
|
public string Key { get; } = "agate";
|
||||||
|
|
||||||
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Audio sampling rate argument. Defaults to 48000 (Hz)
|
||||||
|
/// </summary>
|
||||||
|
public class AudioSamplingRateArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Audio sampling rate argument. Defaults to 48000 (Hz)
|
|
||||||
/// </summary>
|
|
||||||
public class AudioSamplingRateArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int SamplingRate;
|
public readonly int SamplingRate;
|
||||||
|
|
||||||
public AudioSamplingRateArgument(int samplingRate = 48000)
|
public AudioSamplingRateArgument(int samplingRate = 48000)
|
||||||
{
|
{
|
||||||
SamplingRate = samplingRate;
|
SamplingRate = samplingRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-ar {SamplingRate}";
|
public string Text => $"-ar {SamplingRate}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents parameter of bitstream filter
|
||||||
|
/// </summary>
|
||||||
|
public class BitStreamFilterArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents parameter of bitstream filter
|
|
||||||
/// </summary>
|
|
||||||
public class BitStreamFilterArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly Channel Channel;
|
public readonly Channel Channel;
|
||||||
public readonly Filter Filter;
|
public readonly Filter Filter;
|
||||||
|
|
||||||
|
|
@ -22,5 +22,4 @@ namespace FFMpegCore.Arguments
|
||||||
Channel.Video => $"-bsf:v {Filter.ToString().ToLowerInvariant()}",
|
Channel.Video => $"-bsf:v {Filter.ToString().ToLowerInvariant()}",
|
||||||
_ => string.Empty
|
_ => string.Empty
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class BlackDetectArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
public class BlackDetectArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
public string Key => "blackdetect";
|
|
||||||
|
|
||||||
public string Value { get; }
|
|
||||||
|
|
||||||
public BlackDetectArgument(double minimumDuration = 2.0, double pictureBlackRatioThreshold = 0.98, double pixelBlackThreshold = 0.1)
|
public BlackDetectArgument(double minimumDuration = 2.0, double pictureBlackRatioThreshold = 0.98, double pixelBlackThreshold = 0.1)
|
||||||
{
|
{
|
||||||
Value = $"d={minimumDuration}:pic_th={pictureBlackRatioThreshold}:pix_th={pixelBlackThreshold}";
|
Value = $"d={minimumDuration}:pic_th={pictureBlackRatioThreshold}:pix_th={pixelBlackThreshold}";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public string Key => "blackdetect";
|
||||||
|
|
||||||
|
public string Value { get; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
internal class BlackFrameArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
internal class BlackFrameArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
public string Key => "blackframe";
|
|
||||||
|
|
||||||
public string Value { get; }
|
|
||||||
|
|
||||||
public BlackFrameArgument(int amount = 98, int threshold = 32)
|
public BlackFrameArgument(int amount = 98, int threshold = 32)
|
||||||
{
|
{
|
||||||
Value = $"amount={amount}:threshold={threshold}";
|
Value = $"amount={amount}:threshold={threshold}";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public string Key => "blackframe";
|
||||||
|
|
||||||
|
public string Value { get; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,26 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
{
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents parameter of concat argument
|
/// Represents parameter of concat argument
|
||||||
/// Used for creating video from multiple images or videos
|
/// Used for creating video from multiple images or videos
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ConcatArgument : IInputArgument
|
public class ConcatArgument : IInputArgument
|
||||||
{
|
{
|
||||||
public readonly IEnumerable<string> Values;
|
public readonly IEnumerable<string> Values;
|
||||||
|
|
||||||
public ConcatArgument(IEnumerable<string> values)
|
public ConcatArgument(IEnumerable<string> values)
|
||||||
{
|
{
|
||||||
Values = values;
|
Values = values;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Pre() { }
|
public void Pre() { }
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
|
||||||
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void Post() { }
|
public void Post() { }
|
||||||
|
|
||||||
public string Text => $"-i \"concat:{string.Join(@"|", Values)}\"";
|
public string Text => $"-i \"concat:{string.Join(@"|", Values)}\"";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Constant Rate Factor (CRF) argument
|
||||||
|
/// </summary>
|
||||||
|
public class ConstantRateFactorArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Constant Rate Factor (CRF) argument
|
|
||||||
/// </summary>
|
|
||||||
public class ConstantRateFactorArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int Crf;
|
public readonly int Crf;
|
||||||
|
|
||||||
public ConstantRateFactorArgument(int crf)
|
public ConstantRateFactorArgument(int crf)
|
||||||
|
|
@ -18,5 +18,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-crf {Crf}";
|
public string Text => $"-crf {Crf}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents parameter of copy parameter
|
||||||
|
/// Defines if channel (audio, video or both) should be copied to output file
|
||||||
|
/// </summary>
|
||||||
|
public class CopyArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents parameter of copy parameter
|
|
||||||
/// Defines if channel (audio, video or both) should be copied to output file
|
|
||||||
/// </summary>
|
|
||||||
public class CopyArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly Channel Channel;
|
public readonly Channel Channel;
|
||||||
|
|
||||||
public CopyArgument(Channel channel = Channel.Both)
|
public CopyArgument(Channel channel = Channel.Both)
|
||||||
{
|
{
|
||||||
Channel = channel;
|
Channel = channel;
|
||||||
|
|
@ -19,5 +20,4 @@ namespace FFMpegCore.Arguments
|
||||||
Channel.Both => "-c:a copy -c:v copy",
|
Channel.Both => "-c:a copy -c:v copy",
|
||||||
_ => $"-c{Channel.StreamType()} copy"
|
_ => $"-c{Channel.StreamType()} copy"
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a copy codec parameter
|
||||||
|
/// </summary>
|
||||||
|
public class CopyCodecArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
public string Text => "-codec copy";
|
||||||
/// Represents a copy codec parameter
|
|
||||||
/// </summary>
|
|
||||||
public class CopyCodecArgument : IArgument
|
|
||||||
{
|
|
||||||
public string Text => $"-codec copy";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class CropArgument : IArgument
|
||||||
{
|
{
|
||||||
public class CropArgument : IArgument
|
public readonly int Left;
|
||||||
{
|
|
||||||
public readonly Size? Size;
|
public readonly Size? Size;
|
||||||
public readonly int Top;
|
public readonly int Top;
|
||||||
public readonly int Left;
|
|
||||||
|
|
||||||
public CropArgument(Size? size, int top, int left)
|
public CropArgument(Size? size, int top, int left)
|
||||||
{
|
{
|
||||||
|
|
@ -18,5 +18,4 @@ namespace FFMpegCore.Arguments
|
||||||
public CropArgument(int width, int height, int top, int left) : this(new Size(width, height), top, left) { }
|
public CropArgument(int width, int height, int top, int left) : this(new Size(width, height), top, left) { }
|
||||||
|
|
||||||
public string Text => Size == null ? string.Empty : $"-vf crop={Size.Value.Width}:{Size.Value.Height}:{Left}:{Top}";
|
public string Text => Size == null ? string.Empty : $"-vf crop={Size.Value.Width}:{Size.Value.Height}:{Left}:{Top}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class CustomArgument : IArgument
|
||||||
{
|
{
|
||||||
public class CustomArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly string Argument;
|
public readonly string Argument;
|
||||||
|
|
||||||
public CustomArgument(string argument)
|
public CustomArgument(string argument)
|
||||||
|
|
@ -10,5 +10,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => Argument ?? string.Empty;
|
public string Text => Argument ?? string.Empty;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,44 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents parameter of concat argument
|
||||||
|
/// Used for creating video from multiple images or videos
|
||||||
|
/// </summary>
|
||||||
|
public class DemuxConcatArgument : IInputArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"concat_{Guid.NewGuid()}.txt");
|
||||||
/// Represents parameter of concat argument
|
|
||||||
/// Used for creating video from multiple images or videos
|
|
||||||
/// </summary>
|
|
||||||
public class DemuxConcatArgument : IInputArgument
|
|
||||||
{
|
|
||||||
public readonly IEnumerable<string> Values;
|
public readonly IEnumerable<string> Values;
|
||||||
|
|
||||||
public DemuxConcatArgument(IEnumerable<string> values)
|
public DemuxConcatArgument(IEnumerable<string> values)
|
||||||
{
|
{
|
||||||
Values = values.Select(value => $"file '{Escape(value)}'");
|
Values = values.Select(value => $"file '{Escape(value)}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Pre()
|
||||||
|
{
|
||||||
|
File.WriteAllLines(_tempFileName, Values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Post()
|
||||||
|
{
|
||||||
|
File.Delete(_tempFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Text => $"-f concat -safe 0 -i \"{_tempFileName}\"";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Thanks slhck
|
/// Thanks slhck
|
||||||
/// https://superuser.com/a/787651/1089628
|
/// https://superuser.com/a/787651/1089628
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private string Escape(string value) => value.Replace("'", @"'\''");
|
private string Escape(string value)
|
||||||
|
{
|
||||||
private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"concat_{Guid.NewGuid()}.txt");
|
return value.Replace("'", @"'\''");
|
||||||
|
|
||||||
public void Pre() => File.WriteAllLines(_tempFileName, Values);
|
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
|
||||||
public void Post() => File.Delete(_tempFileName);
|
|
||||||
|
|
||||||
public string Text => $"-f concat -safe 0 -i \"{_tempFileName}\"";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents cpu speed parameter
|
||||||
|
/// </summary>
|
||||||
|
public class DisableChannelArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents cpu speed parameter
|
|
||||||
/// </summary>
|
|
||||||
public class DisableChannelArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly Channel Channel;
|
public readonly Channel Channel;
|
||||||
|
|
||||||
public DisableChannelArgument(Channel channel)
|
public DisableChannelArgument(Channel channel)
|
||||||
|
|
@ -26,5 +26,4 @@ namespace FFMpegCore.Arguments
|
||||||
Channel.Audio => "-an",
|
Channel.Audio => "-an",
|
||||||
_ => string.Empty
|
_ => string.Empty
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Drawtext video filter argument
|
||||||
|
/// </summary>
|
||||||
|
public class DrawTextArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Drawtext video filter argument
|
|
||||||
/// </summary>
|
|
||||||
public class DrawTextArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
public readonly DrawTextOptions Options;
|
public readonly DrawTextOptions Options;
|
||||||
|
|
||||||
public DrawTextArgument(DrawTextOptions options)
|
public DrawTextArgument(DrawTextOptions options)
|
||||||
|
|
@ -14,25 +14,33 @@
|
||||||
|
|
||||||
public string Key { get; } = "drawtext";
|
public string Key { get; } = "drawtext";
|
||||||
public string Value => Options.TextInternal;
|
public string Value => Options.TextInternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DrawTextOptions
|
public class DrawTextOptions
|
||||||
{
|
{
|
||||||
public readonly string Text;
|
|
||||||
public readonly string Font;
|
public readonly string Font;
|
||||||
public readonly List<(string key, string value)> Parameters;
|
public readonly List<(string key, string value)> Parameters;
|
||||||
|
public readonly string Text;
|
||||||
|
|
||||||
|
private DrawTextOptions(string text, string font, IEnumerable<(string, string)> parameters)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
Font = font;
|
||||||
|
Parameters = parameters.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string TextInternal => string.Join(":", new[] { ("text", Text), ("fontfile", Font) }.Concat(Parameters).Select(FormatArgumentPair));
|
||||||
|
|
||||||
public static DrawTextOptions Create(string text, string font)
|
public static DrawTextOptions Create(string text, string font)
|
||||||
{
|
{
|
||||||
return new DrawTextOptions(text, font, new List<(string, string)>());
|
return new DrawTextOptions(text, font, new List<(string, string)>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DrawTextOptions Create(string text, string font, params (string key, string value)[] parameters)
|
public static DrawTextOptions Create(string text, string font, params (string key, string value)[] parameters)
|
||||||
{
|
{
|
||||||
return new DrawTextOptions(text, font, parameters);
|
return new DrawTextOptions(text, font, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string TextInternal => string.Join(":", new[] { ("text", Text), ("fontfile", Font) }.Concat(Parameters).Select(FormatArgumentPair));
|
|
||||||
|
|
||||||
private static string FormatArgumentPair((string key, string value) pair)
|
private static string FormatArgumentPair((string key, string value) pair)
|
||||||
{
|
{
|
||||||
return $"{pair.key}={EncloseIfContainsSpace(pair.value)}";
|
return $"{pair.key}={EncloseIfContainsSpace(pair.value)}";
|
||||||
|
|
@ -43,17 +51,9 @@
|
||||||
return input.Contains(" ") ? $"'{input}'" : input;
|
return input.Contains(" ") ? $"'{input}'" : input;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DrawTextOptions(string text, string font, IEnumerable<(string, string)> parameters)
|
|
||||||
{
|
|
||||||
Text = text;
|
|
||||||
Font = font;
|
|
||||||
Parameters = parameters.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public DrawTextOptions WithParameter(string key, string value)
|
public DrawTextOptions WithParameter(string key, string value)
|
||||||
{
|
{
|
||||||
Parameters.Add((key, value));
|
Parameters.Add((key, value));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents duration parameter
|
||||||
|
/// </summary>
|
||||||
|
public class DurationArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents duration parameter
|
|
||||||
/// </summary>
|
|
||||||
public class DurationArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly TimeSpan? Duration;
|
public readonly TimeSpan? Duration;
|
||||||
|
|
||||||
public DurationArgument(TimeSpan? duration)
|
public DurationArgument(TimeSpan? duration)
|
||||||
{
|
{
|
||||||
Duration = duration;
|
Duration = duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => !Duration.HasValue ? string.Empty : $"-t {Duration.Value}";
|
public string Text => !Duration.HasValue ? string.Empty : $"-t {Duration.Value}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class DynamicNormalizerArgument : IAudioFilterArgument
|
||||||
{
|
{
|
||||||
public class DynamicNormalizerArgument : IAudioFilterArgument
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, string> _arguments = new();
|
private readonly Dictionary<string, string> _arguments = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dynamic Audio Normalizer. <see href="https://ffmpeg.org/ffmpeg-filters.html#dynaudnorm"/>
|
/// Dynamic Audio Normalizer. <see href="https://ffmpeg.org/ffmpeg-filters.html#dynaudnorm" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="frameLength">Set the frame length in milliseconds. Must be between 10 to 8000. The default value is 500</param>
|
/// <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="filterWindow">Set the Gaussian filter window size. In range from 3 to 301, must be odd number. The default value is 31</param>
|
||||||
|
|
@ -18,7 +18,8 @@ namespace FFMpegCore.Arguments
|
||||||
/// <param name="enableDcBiasCorrection">Enable DC bias correction. By default is disabled.</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="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>
|
/// <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)
|
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)
|
if (frameLength < 10 || frameLength > 8000)
|
||||||
{
|
{
|
||||||
|
|
@ -69,5 +70,4 @@ namespace FFMpegCore.Arguments
|
||||||
public string Key { get; } = "dynaudnorm";
|
public string Key { get; } = "dynaudnorm";
|
||||||
|
|
||||||
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using FFMpegCore.Extend;
|
using FFMpegCore.Extend;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents seek parameter
|
||||||
|
/// </summary>
|
||||||
|
public class EndSeekArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents seek parameter
|
|
||||||
/// </summary>
|
|
||||||
public class EndSeekArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly TimeSpan? SeekTo;
|
public readonly TimeSpan? SeekTo;
|
||||||
|
|
||||||
public EndSeekArgument(TimeSpan? seekTo)
|
public EndSeekArgument(TimeSpan? seekTo)
|
||||||
|
|
@ -15,5 +15,4 @@ namespace FFMpegCore.Arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => SeekTo.HasValue ? $"-to {SeekTo.Value.ToLongString()}" : string.Empty;
|
public string Text => SeekTo.HasValue ? $"-to {SeekTo.Value.ToLongString()}" : string.Empty;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Faststart argument - for moving moov atom to the start of file
|
||||||
|
/// </summary>
|
||||||
|
public class FaststartArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Faststart argument - for moving moov atom to the start of file
|
|
||||||
/// </summary>
|
|
||||||
public class FaststartArgument : IArgument
|
|
||||||
{
|
|
||||||
public string Text => "-movflags faststart";
|
public string Text => "-movflags faststart";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents force format parameter
|
||||||
|
/// </summary>
|
||||||
|
public class ForceFormatArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents force format parameter
|
|
||||||
/// </summary>
|
|
||||||
public class ForceFormatArgument : IArgument
|
|
||||||
{
|
|
||||||
private readonly string _format;
|
private readonly string _format;
|
||||||
|
|
||||||
public ForceFormatArgument(string format)
|
public ForceFormatArgument(string format)
|
||||||
{
|
{
|
||||||
_format = format;
|
_format = format;
|
||||||
|
|
@ -19,5 +20,4 @@ namespace FFMpegCore.Arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-f {_format}";
|
public string Text => $"-f {_format}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
{
|
|
||||||
public class ForcePixelFormat : IArgument
|
|
||||||
{
|
|
||||||
public string PixelFormat { get; }
|
|
||||||
public string Text => $"-pix_fmt {PixelFormat}";
|
|
||||||
|
|
||||||
|
public class ForcePixelFormat : IArgument
|
||||||
|
{
|
||||||
public ForcePixelFormat(string format)
|
public ForcePixelFormat(string format)
|
||||||
{
|
{
|
||||||
PixelFormat = format;
|
PixelFormat = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ForcePixelFormat(PixelFormat format) : this(format.Name) { }
|
public ForcePixelFormat(PixelFormat format) : this(format.Name) { }
|
||||||
}
|
public string PixelFormat { get; }
|
||||||
|
public string Text => $"-pix_fmt {PixelFormat}";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents frame output count parameter
|
||||||
|
/// </summary>
|
||||||
|
public class FrameOutputCountArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents frame output count parameter
|
|
||||||
/// </summary>
|
|
||||||
public class FrameOutputCountArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int Frames;
|
public readonly int Frames;
|
||||||
|
|
||||||
public FrameOutputCountArgument(int frames)
|
public FrameOutputCountArgument(int frames)
|
||||||
{
|
{
|
||||||
Frames = frames;
|
Frames = frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-vframes {Frames}";
|
public string Text => $"-vframes {Frames}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
namespace FFMpegCore.Arguments
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents frame rate parameter
|
||||||
|
/// </summary>
|
||||||
|
public class FrameRateArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents frame rate parameter
|
|
||||||
/// </summary>
|
|
||||||
public class FrameRateArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly double Framerate;
|
public readonly double Framerate;
|
||||||
|
|
||||||
public FrameRateArgument(double framerate)
|
public FrameRateArgument(double framerate)
|
||||||
|
|
@ -12,6 +14,5 @@
|
||||||
Framerate = framerate;
|
Framerate = framerate;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-r {Framerate.ToString(System.Globalization.CultureInfo.InvariantCulture)}";
|
public string Text => $"-r {Framerate.ToString(CultureInfo.InvariantCulture)}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
{
|
|
||||||
public class GifPaletteArgument : IArgument
|
|
||||||
{
|
|
||||||
private readonly int _streamIndex;
|
|
||||||
|
|
||||||
|
public class GifPaletteArgument : IArgument
|
||||||
|
{
|
||||||
private readonly int _fps;
|
private readonly int _fps;
|
||||||
|
|
||||||
private readonly Size? _size;
|
private readonly Size? _size;
|
||||||
|
private readonly int _streamIndex;
|
||||||
|
|
||||||
public GifPaletteArgument(int streamIndex, int fps, Size? size)
|
public GifPaletteArgument(int streamIndex, int fps, Size? size)
|
||||||
{
|
{
|
||||||
|
|
@ -19,6 +18,6 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
private string ScaleText => _size.HasValue ? $"scale=w={_size.Value.Width}:h={_size.Value.Height}," : string.Empty;
|
private string ScaleText => _size.HasValue ? $"scale=w={_size.Value.Width}:h={_size.Value.Height}," : string.Empty;
|
||||||
|
|
||||||
public string Text => $"-filter_complex \"[{_streamIndex}:v] fps={_fps},{ScaleText}split [a][b];[a] palettegen=max_colors=32 [p];[b][p] paletteuse=dither=bayer\"";
|
public string Text =>
|
||||||
}
|
$"-filter_complex \"[{_streamIndex}:v] fps={_fps},{ScaleText}split [a][b];[a] palettegen=max_colors=32 [p];[b][p] paletteuse=dither=bayer\"";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
{
|
|
||||||
public class HardwareAccelerationArgument : IArgument
|
|
||||||
{
|
|
||||||
public HardwareAccelerationDevice HardwareAccelerationDevice { get; }
|
|
||||||
|
|
||||||
|
public class HardwareAccelerationArgument : IArgument
|
||||||
|
{
|
||||||
public HardwareAccelerationArgument(HardwareAccelerationDevice hardwareAccelerationDevice)
|
public HardwareAccelerationArgument(HardwareAccelerationDevice hardwareAccelerationDevice)
|
||||||
{
|
{
|
||||||
HardwareAccelerationDevice = hardwareAccelerationDevice;
|
HardwareAccelerationDevice = hardwareAccelerationDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HardwareAccelerationDevice HardwareAccelerationDevice { get; }
|
||||||
|
|
||||||
public string Text => $"-hwaccel {HardwareAccelerationDevice.ToString().ToLower()}";
|
public string Text => $"-hwaccel {HardwareAccelerationDevice.ToString().ToLower()}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,62 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class HighPassFilterArgument : IAudioFilterArgument
|
||||||
{
|
{
|
||||||
public class HighPassFilterArgument : IAudioFilterArgument
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, string> _arguments = new();
|
private readonly Dictionary<string, string> _arguments = new();
|
||||||
private readonly List<string> _widthTypes = new() { "h", "q", "o", "s", "k" };
|
|
||||||
private readonly List<string> _transformTypes = new() { "di", "dii", "tdi", "tdii", "latt", "svf", "zdf" };
|
private readonly List<string> _precision = new()
|
||||||
private readonly List<string> _precision = new() { "auto", "s16", "s32", "f32", "f64" };
|
{
|
||||||
|
"auto",
|
||||||
|
"s16",
|
||||||
|
"s32",
|
||||||
|
"f32",
|
||||||
|
"f64"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly List<string> _transformTypes = new()
|
||||||
|
{
|
||||||
|
"di",
|
||||||
|
"dii",
|
||||||
|
"tdi",
|
||||||
|
"tdii",
|
||||||
|
"latt",
|
||||||
|
"svf",
|
||||||
|
"zdf"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly List<string> _widthTypes = new()
|
||||||
|
{
|
||||||
|
"h",
|
||||||
|
"q",
|
||||||
|
"o",
|
||||||
|
"s",
|
||||||
|
"k"
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// HighPass Filter. <see href="https://ffmpeg.org/ffmpeg-filters.html#highpass"/>
|
/// HighPass Filter. <see href="https://ffmpeg.org/ffmpeg-filters.html#highpass" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="frequency">Set frequency in Hz. Default is 3000.</param>
|
/// <param name="frequency">Set frequency in Hz. Default is 3000.</param>
|
||||||
/// <param name="poles">Set number of poles. Default is 2.</param>
|
/// <param name="poles">Set number of poles. Default is 2.</param>
|
||||||
/// <param name="width_type">Set method to specify band-width of filter, possible values are: h, q, o, s, k</param>
|
/// <param name="width_type">Set method to specify band-width of filter, possible values are: h, q, o, s, k</param>
|
||||||
/// <param name="width">Specify the band-width of a filter in width_type units. Applies only to double-pole filter. The default is 0.707q and gives a Butterworth response.</param>
|
/// <param name="width">
|
||||||
|
/// Specify the band-width of a filter in width_type units. Applies only to double-pole filter. The default is 0.707q and
|
||||||
|
/// gives a Butterworth response.
|
||||||
|
/// </param>
|
||||||
/// <param name="mix">How much to use filtered signal in output. Default is 1. Range is between 0 and 1.</param>
|
/// <param name="mix">How much to use filtered signal in output. Default is 1. Range is between 0 and 1.</param>
|
||||||
/// <param name="channels">Specify which channels to filter, by default all available are filtered.</param>
|
/// <param name="channels">Specify which channels to filter, by default all available are filtered.</param>
|
||||||
/// <param name="normalize">Normalize biquad coefficients, by default is disabled. Enabling it will normalize magnitude response at DC to 0dB.</param>
|
/// <param name="normalize">Normalize biquad coefficients, by default is disabled. Enabling it will normalize magnitude response at DC to 0dB.</param>
|
||||||
/// <param name="transform">Set transform type of IIR filter, possible values are: di, dii, tdi, tdii, latt, svf, zdf</param>
|
/// <param name="transform">Set transform type of IIR filter, possible values are: di, dii, tdi, tdii, latt, svf, zdf</param>
|
||||||
/// <param name="precision">Set precison of filtering, possible values are: auto, s16, s32, f32, f64.</param>
|
/// <param name="precision">Set precison of filtering, possible values are: auto, s16, s32, f32, f64.</param>
|
||||||
/// <param name="block_size">Set block size used for reverse IIR processing. If this value is set to high enough value (higher than impulse response length truncated when reaches near zero values) filtering will become linear phase otherwise if not big enough it will just produce nasty artifacts.</param>
|
/// <param name="block_size">
|
||||||
public HighPassFilterArgument(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707, double mix = 1, string channels = "", bool normalize = false, string transform = "", string precision = "auto", int? block_size = null)
|
/// Set block size used for reverse IIR processing. If this value is set to high enough value (higher than impulse
|
||||||
|
/// response length truncated when reaches near zero values) filtering will become linear phase otherwise if not big enough it will just
|
||||||
|
/// produce nasty artifacts.
|
||||||
|
/// </param>
|
||||||
|
public HighPassFilterArgument(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707, double mix = 1, string channels = "",
|
||||||
|
bool normalize = false, string transform = "", string precision = "auto", int? block_size = null)
|
||||||
{
|
{
|
||||||
if (frequency < 0)
|
if (frequency < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +70,7 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
if (!_widthTypes.Contains(width_type))
|
if (!_widthTypes.Contains(width_type))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(width_type), "Width type must be either " + _widthTypes.ToString());
|
throw new ArgumentOutOfRangeException(nameof(width_type), "Width type must be either " + _widthTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mix < 0 || mix > 1)
|
if (mix < 0 || mix > 1)
|
||||||
|
|
@ -45,7 +80,7 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
if (!_precision.Contains(precision))
|
if (!_precision.Contains(precision))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(precision), "Precision must be either " + _precision.ToString());
|
throw new ArgumentOutOfRangeException(nameof(precision), "Precision must be either " + _precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
_arguments.Add("f", frequency.ToString("0.00", CultureInfo.InvariantCulture));
|
_arguments.Add("f", frequency.ToString("0.00", CultureInfo.InvariantCulture));
|
||||||
|
|
@ -74,5 +109,4 @@ namespace FFMpegCore.Arguments
|
||||||
public string Key { get; } = "highpass";
|
public string Key { get; } = "highpass";
|
||||||
|
|
||||||
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public interface IArgument
|
||||||
{
|
{
|
||||||
public interface IArgument
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The textual representation of the argument
|
/// The textual representation of the argument
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Text { get; }
|
string Text { get; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class ID3V2VersionArgument : IArgument
|
||||||
{
|
{
|
||||||
public class ID3V2VersionArgument : IArgument
|
|
||||||
{
|
|
||||||
private readonly int _version;
|
private readonly int _version;
|
||||||
|
|
||||||
public ID3V2VersionArgument(int version)
|
public ID3V2VersionArgument(int version)
|
||||||
|
|
@ -10,5 +10,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-id3v2_version {_version}";
|
public string Text => $"-id3v2_version {_version}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public interface IDynamicArgument
|
||||||
{
|
{
|
||||||
public interface IDynamicArgument
|
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Same as <see cref="IArgument.Text"/>, but this receives the arguments generated before as parameter
|
/// Same as <see cref="IArgument.Text" />, but this receives the arguments generated before as parameter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
//public string GetText(StringBuilder context);
|
//public string GetText(StringBuilder context);
|
||||||
string GetText(IEnumerable<IArgument> context);
|
string GetText(IEnumerable<IArgument> context);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public interface IInputArgument : IInputOutputArgument
|
||||||
{
|
{
|
||||||
public interface IInputArgument : IInputOutputArgument
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public interface IInputOutputArgument : IArgument
|
||||||
{
|
{
|
||||||
public interface IInputOutputArgument : IArgument
|
|
||||||
{
|
|
||||||
void Pre();
|
void Pre();
|
||||||
Task During(CancellationToken cancellationToken = default);
|
Task During(CancellationToken cancellationToken = default);
|
||||||
void Post();
|
void Post();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public interface IOutputArgument : IInputOutputArgument
|
||||||
{
|
{
|
||||||
public interface IOutputArgument : IInputOutputArgument
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents input parameter
|
||||||
|
/// </summary>
|
||||||
|
public class InputArgument : IInputArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents input parameter
|
|
||||||
/// </summary>
|
|
||||||
public class InputArgument : IInputArgument
|
|
||||||
{
|
|
||||||
public readonly bool VerifyExists;
|
|
||||||
public readonly string FilePath;
|
public readonly string FilePath;
|
||||||
|
public readonly bool VerifyExists;
|
||||||
|
|
||||||
public InputArgument(bool verifyExists, string filePaths)
|
public InputArgument(bool verifyExists, string filePaths)
|
||||||
{
|
{
|
||||||
|
|
@ -24,9 +24,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void Post() { }
|
public void Post() { }
|
||||||
|
|
||||||
public string Text => $"-i \"{FilePath}\"";
|
public string Text => $"-i \"{FilePath}\"";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an input device parameter
|
||||||
|
/// </summary>
|
||||||
|
public class InputDeviceArgument : IInputArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents an input device parameter
|
|
||||||
/// </summary>
|
|
||||||
public class InputDeviceArgument : IInputArgument
|
|
||||||
{
|
|
||||||
private readonly string Device;
|
private readonly string Device;
|
||||||
|
|
||||||
public InputDeviceArgument(string device)
|
public InputDeviceArgument(string device)
|
||||||
|
|
@ -12,12 +12,14 @@
|
||||||
Device = device;
|
Device = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void Pre() { }
|
public void Pre() { }
|
||||||
|
|
||||||
public void Post() { }
|
public void Post() { }
|
||||||
|
|
||||||
public string Text => $"-i {Device}";
|
public string Text => $"-i {Device}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents input parameter for a named pipe
|
||||||
|
/// </summary>
|
||||||
|
public class InputPipeArgument : PipeArgument, IInputArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents input parameter for a named pipe
|
|
||||||
/// </summary>
|
|
||||||
public class InputPipeArgument : PipeArgument, IInputArgument
|
|
||||||
{
|
|
||||||
public readonly IPipeSource Writer;
|
public readonly IPipeSource Writer;
|
||||||
|
|
||||||
public InputPipeArgument(IPipeSource writer) : base(PipeDirection.Out)
|
public InputPipeArgument(IPipeSource writer) : base(PipeDirection.Out)
|
||||||
|
|
@ -27,5 +27,4 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
await Writer.WriteAsync(Pipe, token).ConfigureAwait(false);
|
await Writer.WriteAsync(Pipe, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents loop parameter
|
||||||
|
/// </summary>
|
||||||
|
public class LoopArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents loop parameter
|
|
||||||
/// </summary>
|
|
||||||
public class LoopArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int Times;
|
public readonly int Times;
|
||||||
|
|
||||||
public LoopArgument(int times)
|
public LoopArgument(int times)
|
||||||
{
|
{
|
||||||
Times = times;
|
Times = times;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-loop {Times}";
|
public string Text => $"-loop {Times}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,62 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class LowPassFilterArgument : IAudioFilterArgument
|
||||||
{
|
{
|
||||||
public class LowPassFilterArgument : IAudioFilterArgument
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, string> _arguments = new();
|
private readonly Dictionary<string, string> _arguments = new();
|
||||||
private readonly List<string> _widthTypes = new() { "h", "q", "o", "s", "k" };
|
|
||||||
private readonly List<string> _transformTypes = new() { "di", "dii", "tdi", "tdii", "latt", "svf", "zdf" };
|
private readonly List<string> _precision = new()
|
||||||
private readonly List<string> _precision = new() { "auto", "s16", "s32", "f32", "f64" };
|
{
|
||||||
|
"auto",
|
||||||
|
"s16",
|
||||||
|
"s32",
|
||||||
|
"f32",
|
||||||
|
"f64"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly List<string> _transformTypes = new()
|
||||||
|
{
|
||||||
|
"di",
|
||||||
|
"dii",
|
||||||
|
"tdi",
|
||||||
|
"tdii",
|
||||||
|
"latt",
|
||||||
|
"svf",
|
||||||
|
"zdf"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly List<string> _widthTypes = new()
|
||||||
|
{
|
||||||
|
"h",
|
||||||
|
"q",
|
||||||
|
"o",
|
||||||
|
"s",
|
||||||
|
"k"
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// LowPass Filter. <see href="https://ffmpeg.org/ffmpeg-filters.html#lowpass"/>
|
/// LowPass Filter. <see href="https://ffmpeg.org/ffmpeg-filters.html#lowpass" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="frequency">Set frequency in Hz. Default is 3000.</param>
|
/// <param name="frequency">Set frequency in Hz. Default is 3000.</param>
|
||||||
/// <param name="poles">Set number of poles. Default is 2.</param>
|
/// <param name="poles">Set number of poles. Default is 2.</param>
|
||||||
/// <param name="width_type">Set method to specify band-width of filter, possible values are: h, q, o, s, k</param>
|
/// <param name="width_type">Set method to specify band-width of filter, possible values are: h, q, o, s, k</param>
|
||||||
/// <param name="width">Specify the band-width of a filter in width_type units. Applies only to double-pole filter. The default is 0.707q and gives a Butterworth response.</param>
|
/// <param name="width">
|
||||||
|
/// Specify the band-width of a filter in width_type units. Applies only to double-pole filter. The default is 0.707q and
|
||||||
|
/// gives a Butterworth response.
|
||||||
|
/// </param>
|
||||||
/// <param name="mix">How much to use filtered signal in output. Default is 1. Range is between 0 and 1.</param>
|
/// <param name="mix">How much to use filtered signal in output. Default is 1. Range is between 0 and 1.</param>
|
||||||
/// <param name="channels">Specify which channels to filter, by default all available are filtered.</param>
|
/// <param name="channels">Specify which channels to filter, by default all available are filtered.</param>
|
||||||
/// <param name="normalize">Normalize biquad coefficients, by default is disabled. Enabling it will normalize magnitude response at DC to 0dB.</param>
|
/// <param name="normalize">Normalize biquad coefficients, by default is disabled. Enabling it will normalize magnitude response at DC to 0dB.</param>
|
||||||
/// <param name="transform">Set transform type of IIR filter, possible values are: di, dii, tdi, tdii, latt, svf, zdf</param>
|
/// <param name="transform">Set transform type of IIR filter, possible values are: di, dii, tdi, tdii, latt, svf, zdf</param>
|
||||||
/// <param name="precision">Set precison of filtering, possible values are: auto, s16, s32, f32, f64.</param>
|
/// <param name="precision">Set precison of filtering, possible values are: auto, s16, s32, f32, f64.</param>
|
||||||
/// <param name="block_size">Set block size used for reverse IIR processing. If this value is set to high enough value (higher than impulse response length truncated when reaches near zero values) filtering will become linear phase otherwise if not big enough it will just produce nasty artifacts.</param>
|
/// <param name="block_size">
|
||||||
public LowPassFilterArgument(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707, double mix = 1, string channels = "", bool normalize = false, string transform = "", string precision = "auto", int? block_size = null)
|
/// Set block size used for reverse IIR processing. If this value is set to high enough value (higher than impulse
|
||||||
|
/// response length truncated when reaches near zero values) filtering will become linear phase otherwise if not big enough it will just
|
||||||
|
/// produce nasty artifacts.
|
||||||
|
/// </param>
|
||||||
|
public LowPassFilterArgument(double frequency = 3000, int poles = 2, string width_type = "q", double width = 0.707, double mix = 1, string channels = "",
|
||||||
|
bool normalize = false, string transform = "", string precision = "auto", int? block_size = null)
|
||||||
{
|
{
|
||||||
if (frequency < 0)
|
if (frequency < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -35,7 +70,7 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
if (!_widthTypes.Contains(width_type))
|
if (!_widthTypes.Contains(width_type))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(width_type), "Width type must be either " + _widthTypes.ToString());
|
throw new ArgumentOutOfRangeException(nameof(width_type), "Width type must be either " + _widthTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mix < 0 || mix > 1)
|
if (mix < 0 || mix > 1)
|
||||||
|
|
@ -45,7 +80,7 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
if (!_precision.Contains(precision))
|
if (!_precision.Contains(precision))
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException(nameof(precision), "Precision must be either " + _precision.ToString());
|
throw new ArgumentOutOfRangeException(nameof(precision), "Precision must be either " + _precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
_arguments.Add("f", frequency.ToString("0.00", CultureInfo.InvariantCulture));
|
_arguments.Add("f", frequency.ToString("0.00", CultureInfo.InvariantCulture));
|
||||||
|
|
@ -74,5 +109,4 @@ namespace FFMpegCore.Arguments
|
||||||
public string Key { get; } = "lowpass";
|
public string Key { get; } = "lowpass";
|
||||||
|
|
||||||
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
{
|
|
||||||
public class MapMetadataArgument : IInputArgument, IDynamicArgument
|
|
||||||
{
|
|
||||||
private readonly int? _inputIndex;
|
|
||||||
|
|
||||||
public string Text => GetText(null);
|
public class MapMetadataArgument : IInputArgument, IDynamicArgument
|
||||||
|
{
|
||||||
|
private readonly int? _inputIndex;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Null means it takes the last input used before this argument
|
/// Null means it takes the last input used before this argument
|
||||||
|
|
@ -37,6 +35,8 @@
|
||||||
return $"-map_metadata {index}";
|
return $"-map_metadata {index}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Text => GetText(null);
|
||||||
|
|
||||||
public Task During(CancellationToken cancellationToken = default)
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
@ -49,5 +49,4 @@
|
||||||
public void Pre()
|
public void Pre()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents choice of stream by the stream specifier
|
||||||
|
/// </summary>
|
||||||
|
public class MapStreamArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents choice of stream by the stream specifier
|
|
||||||
/// </summary>
|
|
||||||
public class MapStreamArgument : IArgument
|
|
||||||
{
|
|
||||||
private readonly int _inputFileIndex;
|
|
||||||
private readonly int _streamIndex;
|
|
||||||
private readonly Channel _channel;
|
private readonly Channel _channel;
|
||||||
|
private readonly int _inputFileIndex;
|
||||||
private readonly bool _negativeMap;
|
private readonly bool _negativeMap;
|
||||||
|
private readonly int _streamIndex;
|
||||||
|
|
||||||
public MapStreamArgument(int streamIndex, int inputFileIndex, Channel channel = Channel.All, bool negativeMap = false)
|
public MapStreamArgument(int streamIndex, int inputFileIndex, Channel channel = Channel.All, bool negativeMap = false)
|
||||||
{
|
{
|
||||||
|
|
@ -27,5 +27,4 @@ namespace FFMpegCore.Arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-map {(_negativeMap ? "-" : "")}{_inputFileIndex}{_channel.StreamType()}:{_streamIndex}";
|
public string Text => $"-map {(_negativeMap ? "-" : "")}{_inputFileIndex}{_channel.StreamType()}:{_streamIndex}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class MetaDataArgument : IInputArgument, IDynamicArgument
|
||||||
{
|
{
|
||||||
public class MetaDataArgument : IInputArgument, IDynamicArgument
|
|
||||||
{
|
|
||||||
private readonly string _metaDataContent;
|
private readonly string _metaDataContent;
|
||||||
private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"metadata_{Guid.NewGuid()}.txt");
|
private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"metadata_{Guid.NewGuid()}.txt");
|
||||||
|
|
||||||
|
|
@ -10,14 +10,6 @@
|
||||||
_metaDataContent = metaDataContent;
|
_metaDataContent = metaDataContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => GetText(null);
|
|
||||||
|
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
|
||||||
|
|
||||||
public void Pre() => File.WriteAllText(_tempFileName, _metaDataContent);
|
|
||||||
|
|
||||||
public void Post() => File.Delete(_tempFileName);
|
|
||||||
|
|
||||||
public string GetText(IEnumerable<IArgument>? arguments)
|
public string GetText(IEnumerable<IArgument>? arguments)
|
||||||
{
|
{
|
||||||
arguments ??= Enumerable.Empty<IArgument>();
|
arguments ??= Enumerable.Empty<IArgument>();
|
||||||
|
|
@ -29,5 +21,21 @@
|
||||||
|
|
||||||
return $"-i \"{_tempFileName}\" -map_metadata {index}";
|
return $"-i \"{_tempFileName}\" -map_metadata {index}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string Text => GetText(null);
|
||||||
|
|
||||||
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Pre()
|
||||||
|
{
|
||||||
|
File.WriteAllText(_tempFileName, _metaDataContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Post()
|
||||||
|
{
|
||||||
|
File.Delete(_tempFileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents input parameters for multiple files
|
||||||
|
/// </summary>
|
||||||
|
public class MultiInputArgument : IInputArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents input parameters for multiple files
|
|
||||||
/// </summary>
|
|
||||||
public class MultiInputArgument : IInputArgument
|
|
||||||
{
|
|
||||||
public readonly bool VerifyExists;
|
|
||||||
public readonly IEnumerable<string> FilePaths;
|
public readonly IEnumerable<string> FilePaths;
|
||||||
|
public readonly bool VerifyExists;
|
||||||
|
|
||||||
public MultiInputArgument(bool verifyExists, IEnumerable<string> filePaths)
|
public MultiInputArgument(bool verifyExists, IEnumerable<string> filePaths)
|
||||||
{
|
{
|
||||||
|
|
@ -36,12 +36,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void Post() { }
|
public void Post() { }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Generates a combined input argument text for all file paths
|
/// Generates a combined input argument text for all file paths
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Text => string.Join(" ", FilePaths.Select(filePath => $"-i \"{filePath}\""));
|
public string Text => string.Join(" ", FilePaths.Select(filePath => $"-i \"{filePath}\""));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents output parameter
|
||||||
|
/// </summary>
|
||||||
|
public class OutputArgument : IOutputArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents output parameter
|
|
||||||
/// </summary>
|
|
||||||
public class OutputArgument : IOutputArgument
|
|
||||||
{
|
|
||||||
public readonly string Path;
|
|
||||||
public readonly bool Overwrite;
|
public readonly bool Overwrite;
|
||||||
|
public readonly string Path;
|
||||||
|
|
||||||
public OutputArgument(string path, bool overwrite = true)
|
public OutputArgument(string path, bool overwrite = true)
|
||||||
{
|
{
|
||||||
|
|
@ -16,6 +16,10 @@ namespace FFMpegCore.Arguments
|
||||||
Overwrite = overwrite;
|
Overwrite = overwrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OutputArgument(FileInfo value) : this(value.FullName) { }
|
||||||
|
|
||||||
|
public OutputArgument(Uri value) : this(value.AbsolutePath) { }
|
||||||
|
|
||||||
public void Pre()
|
public void Pre()
|
||||||
{
|
{
|
||||||
if (!Overwrite && File.Exists(Path))
|
if (!Overwrite && File.Exists(Path))
|
||||||
|
|
@ -23,15 +27,15 @@ namespace FFMpegCore.Arguments
|
||||||
throw new FFMpegException(FFMpegExceptionType.File, "Output file already exists and overwrite is disabled");
|
throw new FFMpegException(FFMpegExceptionType.File, "Output file already exists and overwrite is disabled");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
|
||||||
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void Post()
|
public void Post()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputArgument(FileInfo value) : this(value.FullName) { }
|
|
||||||
|
|
||||||
public OutputArgument(Uri value) : this(value.AbsolutePath) { }
|
|
||||||
|
|
||||||
public string Text => $"\"{Path}\"{(Overwrite ? " -y" : string.Empty)}";
|
public string Text => $"\"{Path}\"{(Overwrite ? " -y" : string.Empty)}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class OutputPipeArgument : PipeArgument, IOutputArgument
|
||||||
{
|
{
|
||||||
public class OutputPipeArgument : PipeArgument, IOutputArgument
|
|
||||||
{
|
|
||||||
public readonly IPipeSink Reader;
|
public readonly IPipeSink Reader;
|
||||||
|
|
||||||
public OutputPipeArgument(IPipeSink reader) : base(PipeDirection.In)
|
public OutputPipeArgument(IPipeSink reader) : base(PipeDirection.In)
|
||||||
|
|
@ -24,5 +24,4 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
await Reader.ReadAsync(Pipe, token).ConfigureAwait(false);
|
await Reader.ReadAsync(Pipe, token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
|
namespace FFMpegCore.Arguments;
|
||||||
namespace FFMpegCore.Arguments
|
|
||||||
|
internal class OutputTeeArgument : IOutputArgument
|
||||||
{
|
{
|
||||||
internal class OutputTeeArgument : IOutputArgument
|
|
||||||
{
|
|
||||||
private readonly FFMpegMultiOutputOptions _options;
|
private readonly FFMpegMultiOutputOptions _options;
|
||||||
|
|
||||||
public OutputTeeArgument(FFMpegMultiOutputOptions options)
|
public OutputTeeArgument(FFMpegMultiOutputOptions options)
|
||||||
|
|
@ -17,7 +16,10 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
public string Text => $"-f tee \"{string.Join("|", _options.Outputs.Select(MapOptions))}\"";
|
public string Text => $"-f tee \"{string.Join("|", _options.Outputs.Select(MapOptions))}\"";
|
||||||
|
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void Post()
|
public void Post()
|
||||||
{
|
{
|
||||||
|
|
@ -46,12 +48,12 @@ namespace FFMpegCore.Arguments
|
||||||
{
|
{
|
||||||
return map.Text.Replace("-map ", "select=\\'") + "\\'";
|
return map.Text.Replace("-map ", "select=\\'") + "\\'";
|
||||||
}
|
}
|
||||||
else if (argument is BitStreamFilterArgument bitstreamFilter)
|
|
||||||
|
if (argument is BitStreamFilterArgument bitstreamFilter)
|
||||||
{
|
{
|
||||||
return bitstreamFilter.Text.Replace("-bsf:", "bsfs/").Replace(' ', '=');
|
return bitstreamFilter.Text.Replace("-bsf:", "bsfs/").Replace(' ', '=');
|
||||||
}
|
}
|
||||||
|
|
||||||
return argument.Text.TrimStart('-').Replace(' ', '=');
|
return argument.Text.TrimStart('-').Replace(' ', '=');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents outputting to url using supported protocols
|
||||||
|
/// See http://ffmpeg.org/ffmpeg-protocols.html
|
||||||
|
/// </summary>
|
||||||
|
public class OutputUrlArgument : IOutputArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents outputting to url using supported protocols
|
|
||||||
/// See http://ffmpeg.org/ffmpeg-protocols.html
|
|
||||||
/// </summary>
|
|
||||||
public class OutputUrlArgument : IOutputArgument
|
|
||||||
{
|
|
||||||
public readonly string Url;
|
public readonly string Url;
|
||||||
|
|
||||||
public OutputUrlArgument(string url)
|
public OutputUrlArgument(string url)
|
||||||
|
|
@ -15,10 +15,12 @@
|
||||||
|
|
||||||
public void Post() { }
|
public void Post() { }
|
||||||
|
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
public Task During(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
public void Pre() { }
|
public void Pre() { }
|
||||||
|
|
||||||
public string Text => Url;
|
public string Text => Url;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents overwrite parameter
|
||||||
|
/// If output file should be overwritten if exists
|
||||||
|
/// </summary>
|
||||||
|
public class OverwriteArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents overwrite parameter
|
|
||||||
/// If output file should be overwritten if exists
|
|
||||||
/// </summary>
|
|
||||||
public class OverwriteArgument : IArgument
|
|
||||||
{
|
|
||||||
public string Text => "-y";
|
public string Text => "-y";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using FFMpegCore.Extend;
|
using FFMpegCore.Extend;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class PadArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
public class PadArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
private readonly PadOptions _options;
|
private readonly PadOptions _options;
|
||||||
|
|
||||||
public PadArgument(PadOptions options)
|
public PadArgument(PadOptions options)
|
||||||
|
|
@ -13,31 +13,12 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
public string Key => "pad";
|
public string Key => "pad";
|
||||||
public string Value => _options.TextInternal;
|
public string Value => _options.TextInternal;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
public class PadOptions
|
||||||
|
{
|
||||||
public class PadOptions
|
|
||||||
{
|
|
||||||
public readonly Dictionary<string, string> Parameters = new();
|
public readonly Dictionary<string, string> Parameters = new();
|
||||||
|
|
||||||
internal string TextInternal => string.Join(":", Parameters.Select(parameter => parameter.FormatArgumentPair(true)));
|
|
||||||
|
|
||||||
public static PadOptions Create(string? width, string? height)
|
|
||||||
{
|
|
||||||
return new PadOptions(width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PadOptions Create(string aspectRatio)
|
|
||||||
{
|
|
||||||
return new PadOptions(aspectRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PadOptions WithParameter(string key, string value)
|
|
||||||
{
|
|
||||||
Parameters.Add(key, value);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private PadOptions(string? width, string? height)
|
private PadOptions(string? width, string? height)
|
||||||
{
|
{
|
||||||
if (width == null && height == null)
|
if (width == null && height == null)
|
||||||
|
|
@ -60,5 +41,22 @@ namespace FFMpegCore.Arguments
|
||||||
{
|
{
|
||||||
Parameters.Add("aspect", aspectRatio);
|
Parameters.Add("aspect", aspectRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal string TextInternal => string.Join(":", Parameters.Select(parameter => parameter.FormatArgumentPair(true)));
|
||||||
|
|
||||||
|
public static PadOptions Create(string? width, string? height)
|
||||||
|
{
|
||||||
|
return new PadOptions(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PadOptions Create(string aspectRatio)
|
||||||
|
{
|
||||||
|
return new PadOptions(aspectRatio);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PadOptions WithParameter(string key, string value)
|
||||||
|
{
|
||||||
|
Parameters.Add(key, value);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mix channels with specific gain levels.
|
||||||
|
/// </summary>
|
||||||
|
public class PanArgument : IAudioFilterArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Mix channels with specific gain levels.
|
|
||||||
/// </summary>
|
|
||||||
public class PanArgument : IAudioFilterArgument
|
|
||||||
{
|
|
||||||
public readonly string ChannelLayout;
|
|
||||||
private readonly string[] _outputDefinitions;
|
private readonly string[] _outputDefinitions;
|
||||||
|
public readonly string ChannelLayout;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mix channels with specific gain levels <see href="https://ffmpeg.org/ffmpeg-filters.html#toc-pan-1"/>
|
/// Mix channels with specific gain levels <see href="https://ffmpeg.org/ffmpeg-filters.html#toc-pan-1" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channelLayout">
|
/// <param name="channelLayout">
|
||||||
/// Represent the output channel layout. Like "stereo", "mono", "2.1", "5.1"
|
/// Represent the output channel layout. Like "stereo", "mono", "2.1", "5.1"
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Mix channels with specific gain levels <see href="https://ffmpeg.org/ffmpeg-filters.html#toc-pan-1"/>
|
/// Mix channels with specific gain levels <see href="https://ffmpeg.org/ffmpeg-filters.html#toc-pan-1" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channels">Number of channels in output file</param>
|
/// <param name="channels">Number of channels in output file</param>
|
||||||
/// <param name="outputDefinitions">
|
/// <param name="outputDefinitions">
|
||||||
|
|
@ -57,5 +57,4 @@
|
||||||
|
|
||||||
public string Value =>
|
public string Value =>
|
||||||
string.Join("|", Enumerable.Empty<string>().Append(ChannelLayout).Concat(_outputDefinitions));
|
string.Join("|", Enumerable.Empty<string>().Append(ChannelLayout).Concat(_outputDefinitions));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,10 @@
|
||||||
using System.IO.Pipes;
|
using System.IO.Pipes;
|
||||||
using FFMpegCore.Pipes;
|
using FFMpegCore.Pipes;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
{
|
|
||||||
public abstract class PipeArgument
|
|
||||||
{
|
|
||||||
private string PipeName { get; }
|
|
||||||
public string PipePath => PipeHelpers.GetPipePath(PipeName);
|
|
||||||
|
|
||||||
protected NamedPipeServerStream Pipe { get; private set; } = null!;
|
public abstract class PipeArgument
|
||||||
|
{
|
||||||
private readonly PipeDirection _direction;
|
private readonly PipeDirection _direction;
|
||||||
|
|
||||||
protected PipeArgument(PipeDirection direction)
|
protected PipeArgument(PipeDirection direction)
|
||||||
|
|
@ -18,6 +14,12 @@ namespace FFMpegCore.Arguments
|
||||||
_direction = direction;
|
_direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string PipeName { get; }
|
||||||
|
public string PipePath => PipeHelpers.GetPipePath(PipeName);
|
||||||
|
|
||||||
|
protected NamedPipeServerStream Pipe { get; private set; } = null!;
|
||||||
|
public abstract string Text { get; }
|
||||||
|
|
||||||
public void Pre()
|
public void Pre()
|
||||||
{
|
{
|
||||||
if (Pipe != null)
|
if (Pipe != null)
|
||||||
|
|
@ -56,6 +58,4 @@ namespace FFMpegCore.Arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract Task ProcessDataAsync(CancellationToken token);
|
protected abstract Task ProcessDataAsync(CancellationToken token);
|
||||||
public abstract string Text { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove metadata argument
|
||||||
|
/// </summary>
|
||||||
|
public class RemoveMetadataArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Remove metadata argument
|
|
||||||
/// </summary>
|
|
||||||
public class RemoveMetadataArgument : IArgument
|
|
||||||
{
|
|
||||||
public string Text => "-map_metadata -1";
|
public string Text => "-map_metadata -1";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents scale parameter
|
||||||
|
/// </summary>
|
||||||
|
public class ScaleArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents scale parameter
|
|
||||||
/// </summary>
|
|
||||||
public class ScaleArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
public readonly Size? Size;
|
public readonly Size? Size;
|
||||||
|
|
||||||
public ScaleArgument(Size? size)
|
public ScaleArgument(Size? size)
|
||||||
{
|
{
|
||||||
Size = size;
|
Size = size;
|
||||||
|
|
@ -18,10 +19,9 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
public ScaleArgument(VideoSize videosize)
|
public ScaleArgument(VideoSize videosize)
|
||||||
{
|
{
|
||||||
Size = videosize == VideoSize.Original ? null : (Size?)new Size(-1, (int)videosize);
|
Size = videosize == VideoSize.Original ? null : new Size(-1, (int)videosize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Key { get; } = "scale";
|
public string Key { get; } = "scale";
|
||||||
public string Value => Size == null ? string.Empty : $"{Size.Value.Width}:{Size.Value.Height}";
|
public string Value => Size == null ? string.Empty : $"{Size.Value.Width}:{Size.Value.Height}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using FFMpegCore.Extend;
|
using FFMpegCore.Extend;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents seek parameter
|
||||||
|
/// </summary>
|
||||||
|
public class SeekArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents seek parameter
|
|
||||||
/// </summary>
|
|
||||||
public class SeekArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly TimeSpan? SeekTo;
|
public readonly TimeSpan? SeekTo;
|
||||||
|
|
||||||
public SeekArgument(TimeSpan? seekTo)
|
public SeekArgument(TimeSpan? seekTo)
|
||||||
|
|
@ -15,5 +15,4 @@ namespace FFMpegCore.Arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => SeekTo.HasValue ? $"-ss {SeekTo.Value.ToLongString()}" : string.Empty;
|
public string Text => SeekTo.HasValue ? $"-ss {SeekTo.Value.ToLongString()}" : string.Empty;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class SetMirroringArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
public class SetMirroringArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
public SetMirroringArgument(Mirroring mirroring)
|
public SetMirroringArgument(Mirroring mirroring)
|
||||||
{
|
{
|
||||||
Mirroring = mirroring;
|
Mirroring = mirroring;
|
||||||
|
|
@ -20,5 +20,4 @@ namespace FFMpegCore.Arguments
|
||||||
Mirroring.Vertical => "vflip",
|
Mirroring.Vertical => "vflip",
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(Mirroring))
|
_ => throw new ArgumentOutOfRangeException(nameof(Mirroring))
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents shortest parameter
|
||||||
|
/// </summary>
|
||||||
|
public class ShortestArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents shortest parameter
|
|
||||||
/// </summary>
|
|
||||||
public class ShortestArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly bool Shortest;
|
public readonly bool Shortest;
|
||||||
|
|
||||||
public ShortestArgument(bool shortest)
|
public ShortestArgument(bool shortest)
|
||||||
|
|
@ -13,5 +13,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => Shortest ? "-shortest" : string.Empty;
|
public string Text => Shortest ? "-shortest" : string.Empty;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,24 @@
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class SilenceDetectArgument : IAudioFilterArgument
|
||||||
{
|
{
|
||||||
public class SilenceDetectArgument : IAudioFilterArgument
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, string> _arguments = new();
|
private readonly Dictionary<string, string> _arguments = new();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Silence Detection. <see href="https://ffmpeg.org/ffmpeg-filters.html#silencedetect"/>
|
/// Silence Detection. <see href="https://ffmpeg.org/ffmpeg-filters.html#silencedetect" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="noise_type">Set noise type to db (decibel) or ar (amplitude ratio). Default is dB</param>
|
/// <param name="noise_type">Set noise type to db (decibel) or ar (amplitude ratio). Default is dB</param>
|
||||||
/// <param name="noise">Set noise tolerance. Can be specified in dB (in case "dB" is appended to the specified value) or amplitude ratio. Default is -60dB, or 0.001.</param>
|
/// <param name="noise">
|
||||||
/// <param name="duration">Set silence duration until notification (default is 2 seconds). See (ffmpeg-utils)the Time duration section in the ffmpeg-utils(1) manual for the accepted syntax.</param>
|
/// Set noise tolerance. Can be specified in dB (in case "dB" is appended to the specified value) or amplitude ratio.
|
||||||
|
/// Default is -60dB, or 0.001.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="duration">
|
||||||
|
/// Set silence duration until notification (default is 2 seconds). See (ffmpeg-utils)the Time duration section in the
|
||||||
|
/// ffmpeg-utils(1) manual for the accepted syntax.
|
||||||
|
/// </param>
|
||||||
/// <param name="mono">Process each channel separately, instead of combined. By default is disabled.</param>
|
/// <param name="mono">Process each channel separately, instead of combined. By default is disabled.</param>
|
||||||
|
|
||||||
public SilenceDetectArgument(string noise_type = "db", double noise = 60, double duration = 2, bool mono = false)
|
public SilenceDetectArgument(string noise_type = "db", double noise = 60, double duration = 2, bool mono = false)
|
||||||
{
|
{
|
||||||
if (noise_type == "db")
|
if (noise_type == "db")
|
||||||
|
|
@ -35,5 +41,4 @@ namespace FFMpegCore.Arguments
|
||||||
public string Key { get; } = "silencedetect";
|
public string Key { get; } = "silencedetect";
|
||||||
|
|
||||||
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
public string Value => string.Join(":", _arguments.Select(pair => $"{pair.Key}={pair.Value}"));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents size parameter
|
||||||
|
/// </summary>
|
||||||
|
public class SizeArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents size parameter
|
|
||||||
/// </summary>
|
|
||||||
public class SizeArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly Size? Size;
|
public readonly Size? Size;
|
||||||
|
|
||||||
public SizeArgument(Size? size)
|
public SizeArgument(Size? size)
|
||||||
{
|
{
|
||||||
Size = size;
|
Size = size;
|
||||||
|
|
@ -16,5 +17,4 @@ namespace FFMpegCore.Arguments
|
||||||
public SizeArgument(int width, int height) : this(new Size(width, height)) { }
|
public SizeArgument(int width, int height) : this(new Size(width, height)) { }
|
||||||
|
|
||||||
public string Text => Size == null ? string.Empty : $"-s {Size.Value.Width}x{Size.Value.Height}";
|
public string Text => Size == null ? string.Empty : $"-s {Size.Value.Width}x{Size.Value.Height}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents speed parameter
|
||||||
|
/// </summary>
|
||||||
|
public class SpeedPresetArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents speed parameter
|
|
||||||
/// </summary>
|
|
||||||
public class SpeedPresetArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly Speed Speed;
|
public readonly Speed Speed;
|
||||||
|
|
||||||
public SpeedPresetArgument(Speed speed)
|
public SpeedPresetArgument(Speed speed)
|
||||||
|
|
@ -15,5 +15,4 @@ namespace FFMpegCore.Arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-preset {Speed.ToString().ToLowerInvariant()}";
|
public string Text => $"-preset {Speed.ToString().ToLowerInvariant()}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents start number parameter
|
||||||
|
/// </summary>
|
||||||
|
public class StartNumberArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents start number parameter
|
|
||||||
/// </summary>
|
|
||||||
public class StartNumberArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int StartNumber;
|
public readonly int StartNumber;
|
||||||
|
|
||||||
public StartNumberArgument(int startNumber)
|
public StartNumberArgument(int startNumber)
|
||||||
|
|
@ -13,5 +13,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-start_number {StartNumber}";
|
public string Text => $"-start_number {StartNumber}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using FFMpegCore.Extend;
|
using FFMpegCore.Extend;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class SubtitleHardBurnArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
public class SubtitleHardBurnArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
private readonly SubtitleHardBurnOptions _subtitleHardBurnOptions;
|
private readonly SubtitleHardBurnOptions _subtitleHardBurnOptions;
|
||||||
|
|
||||||
public SubtitleHardBurnArgument(SubtitleHardBurnOptions subtitleHardBurnOptions)
|
public SubtitleHardBurnArgument(SubtitleHardBurnOptions subtitleHardBurnOptions)
|
||||||
|
|
@ -15,16 +15,25 @@ namespace FFMpegCore.Arguments
|
||||||
public string Key => "subtitles";
|
public string Key => "subtitles";
|
||||||
|
|
||||||
public string Value => _subtitleHardBurnOptions.TextInternal;
|
public string Value => _subtitleHardBurnOptions.TextInternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SubtitleHardBurnOptions
|
public class SubtitleHardBurnOptions
|
||||||
{
|
{
|
||||||
private readonly string _subtitle;
|
private readonly string _subtitle;
|
||||||
|
|
||||||
public readonly Dictionary<string, string> Parameters = new();
|
public readonly Dictionary<string, string> Parameters = new();
|
||||||
|
|
||||||
|
private SubtitleHardBurnOptions(string subtitle)
|
||||||
|
{
|
||||||
|
_subtitle = subtitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string TextInternal => string
|
||||||
|
.Join(":", new[] { StringExtensions.EncloseInQuotes(StringExtensions.ToFFmpegLibavfilterPath(_subtitle)) }
|
||||||
|
.Concat(Parameters.Select(parameter => parameter.FormatArgumentPair(true))));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a new <see cref="SubtitleHardBurnOptions"/> using a provided subtitle file or a video file
|
/// Create a new <see cref="SubtitleHardBurnOptions" /> using a provided subtitle file or a video file
|
||||||
/// containing one.
|
/// containing one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="subtitlePath"></param>
|
/// <param name="subtitlePath"></param>
|
||||||
|
|
@ -35,11 +44,6 @@ namespace FFMpegCore.Arguments
|
||||||
return new SubtitleHardBurnOptions(subtitlePath);
|
return new SubtitleHardBurnOptions(subtitlePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SubtitleHardBurnOptions(string subtitle)
|
|
||||||
{
|
|
||||||
_subtitle = subtitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specify the size of the original video, the video for which the ASS file was composed.
|
/// Specify the size of the original video, the video for which the ASS file was composed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -100,16 +104,14 @@ namespace FFMpegCore.Arguments
|
||||||
Parameters.Add(key, value);
|
Parameters.Add(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal string TextInternal => string
|
public class StyleOptions
|
||||||
.Join(":", new[] { StringExtensions.EncloseInQuotes(StringExtensions.ToFFmpegLibavfilterPath(_subtitle)) }
|
{
|
||||||
.Concat(Parameters.Select(parameter => parameter.FormatArgumentPair(enclose: true))));
|
|
||||||
}
|
|
||||||
|
|
||||||
public class StyleOptions
|
|
||||||
{
|
|
||||||
public readonly Dictionary<string, string> Parameters = new();
|
public readonly Dictionary<string, string> Parameters = new();
|
||||||
|
|
||||||
|
internal string TextInternal => string.Join(",", Parameters.Select(parameter => parameter.FormatArgumentPair(false)));
|
||||||
|
|
||||||
public static StyleOptions Create()
|
public static StyleOptions Create()
|
||||||
{
|
{
|
||||||
return new StyleOptions();
|
return new StyleOptions();
|
||||||
|
|
@ -126,7 +128,4 @@ namespace FFMpegCore.Arguments
|
||||||
Parameters.Add(key, value);
|
Parameters.Add(key, value);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal string TextInternal => string.Join(",", Parameters.Select(parameter => parameter.FormatArgumentPair(enclose: false)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents threads parameter
|
||||||
|
/// Number of threads used for video encoding
|
||||||
|
/// </summary>
|
||||||
|
public class ThreadsArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents threads parameter
|
|
||||||
/// Number of threads used for video encoding
|
|
||||||
/// </summary>
|
|
||||||
public class ThreadsArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int Threads;
|
public readonly int Threads;
|
||||||
|
|
||||||
public ThreadsArgument(int threads)
|
public ThreadsArgument(int threads)
|
||||||
{
|
{
|
||||||
Threads = threads;
|
Threads = threads;
|
||||||
|
|
@ -15,5 +16,4 @@
|
||||||
public ThreadsArgument(bool isMultiThreaded) : this(isMultiThreaded ? Environment.ProcessorCount : 1) { }
|
public ThreadsArgument(bool isMultiThreaded) : this(isMultiThreaded ? Environment.ProcessorCount : 1) { }
|
||||||
|
|
||||||
public string Text => $"-threads {Threads}";
|
public string Text => $"-threads {Threads}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Transpose argument.
|
||||||
|
/// 0 = 90CounterCLockwise and Vertical Flip (default)
|
||||||
|
/// 1 = 90Clockwise
|
||||||
|
/// 2 = 90CounterClockwise
|
||||||
|
/// 3 = 90Clockwise and Vertical Flip
|
||||||
|
/// </summary>
|
||||||
|
public class TransposeArgument : IVideoFilterArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Transpose argument.
|
|
||||||
/// 0 = 90CounterCLockwise and Vertical Flip (default)
|
|
||||||
/// 1 = 90Clockwise
|
|
||||||
/// 2 = 90CounterClockwise
|
|
||||||
/// 3 = 90Clockwise and Vertical Flip
|
|
||||||
/// </summary>
|
|
||||||
public class TransposeArgument : IVideoFilterArgument
|
|
||||||
{
|
|
||||||
public readonly Transposition Transposition;
|
public readonly Transposition Transposition;
|
||||||
|
|
||||||
public TransposeArgument(Transposition transposition)
|
public TransposeArgument(Transposition transposition)
|
||||||
{
|
{
|
||||||
Transposition = transposition;
|
Transposition = transposition;
|
||||||
|
|
@ -19,5 +20,4 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
public string Key { get; } = "transpose";
|
public string Key { get; } = "transpose";
|
||||||
public string Value => ((int)Transposition).ToString();
|
public string Value => ((int)Transposition).ToString();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Variable Bitrate Argument (VBR) argument
|
||||||
|
/// </summary>
|
||||||
|
public class VariableBitRateArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Variable Bitrate Argument (VBR) argument
|
|
||||||
/// </summary>
|
|
||||||
public class VariableBitRateArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int Vbr;
|
public readonly int Vbr;
|
||||||
|
|
||||||
public VariableBitRateArgument(int vbr)
|
public VariableBitRateArgument(int vbr)
|
||||||
|
|
@ -18,5 +18,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-vbr {Vbr}";
|
public string Text => $"-vbr {Vbr}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class VerbosityLevelArgument : IArgument
|
||||||
{
|
{
|
||||||
public class VerbosityLevelArgument : IArgument
|
|
||||||
{
|
|
||||||
private readonly VerbosityLevel _verbosityLevel;
|
private readonly VerbosityLevel _verbosityLevel;
|
||||||
|
|
||||||
public VerbosityLevelArgument(VerbosityLevel verbosityLevel)
|
public VerbosityLevelArgument(VerbosityLevel verbosityLevel)
|
||||||
{
|
{
|
||||||
_verbosityLevel = verbosityLevel;
|
_verbosityLevel = verbosityLevel;
|
||||||
}
|
}
|
||||||
public string Text => $"{((int)_verbosityLevel < 32 ? "-hide_banner " : "")}-loglevel {_verbosityLevel.ToString().ToLowerInvariant()}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum VerbosityLevel
|
public string Text => $"{((int)_verbosityLevel < 32 ? "-hide_banner " : "")}-loglevel {_verbosityLevel.ToString().ToLowerInvariant()}";
|
||||||
{
|
}
|
||||||
|
|
||||||
|
public enum VerbosityLevel
|
||||||
|
{
|
||||||
Quiet = -8,
|
Quiet = -8,
|
||||||
Fatal = 8,
|
Fatal = 8,
|
||||||
Error = 16,
|
Error = 16,
|
||||||
|
|
@ -21,5 +22,4 @@
|
||||||
Verbose = 40,
|
Verbose = 40,
|
||||||
Debug = 48,
|
Debug = 48,
|
||||||
Trace = 56
|
Trace = 56
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents video bitrate parameter
|
||||||
|
/// </summary>
|
||||||
|
public class VideoBitrateArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents video bitrate parameter
|
|
||||||
/// </summary>
|
|
||||||
public class VideoBitrateArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly int Bitrate;
|
public readonly int Bitrate;
|
||||||
|
|
||||||
public VideoBitrateArgument(int bitrate)
|
public VideoBitrateArgument(int bitrate)
|
||||||
|
|
@ -13,5 +13,4 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-b:v {Bitrate}k";
|
public string Text => $"-b:v {Bitrate}k";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents video codec parameter
|
||||||
|
/// </summary>
|
||||||
|
public class VideoCodecArgument : IArgument
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Represents video codec parameter
|
|
||||||
/// </summary>
|
|
||||||
public class VideoCodecArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly string Codec;
|
public readonly string Codec;
|
||||||
|
|
||||||
public VideoCodecArgument(string codec)
|
public VideoCodecArgument(string codec)
|
||||||
|
|
@ -26,5 +26,4 @@ namespace FFMpegCore.Arguments
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Text => $"-c:v {Codec}";
|
public string Text => $"-c:v {Codec}";
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Exceptions;
|
using FFMpegCore.Exceptions;
|
||||||
|
|
||||||
namespace FFMpegCore.Arguments
|
namespace FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
public class VideoFiltersArgument : IArgument
|
||||||
{
|
{
|
||||||
public class VideoFiltersArgument : IArgument
|
|
||||||
{
|
|
||||||
public readonly VideoFilterOptions Options;
|
public readonly VideoFilterOptions Options;
|
||||||
|
|
||||||
public VideoFiltersArgument(VideoFilterOptions options)
|
public VideoFiltersArgument(VideoFilterOptions options)
|
||||||
|
|
@ -32,33 +32,71 @@ namespace FFMpegCore.Arguments
|
||||||
|
|
||||||
return $"-vf \"{string.Join(", ", arguments)}\"";
|
return $"-vf \"{string.Join(", ", arguments)}\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IVideoFilterArgument
|
public interface IVideoFilterArgument
|
||||||
{
|
{
|
||||||
string Key { get; }
|
string Key { get; }
|
||||||
string Value { get; }
|
string Value { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VideoFilterOptions
|
public class VideoFilterOptions
|
||||||
{
|
{
|
||||||
public List<IVideoFilterArgument> Arguments { get; } = new();
|
public List<IVideoFilterArgument> Arguments { get; } = new();
|
||||||
|
|
||||||
public VideoFilterOptions Scale(VideoSize videoSize) => WithArgument(new ScaleArgument(videoSize));
|
public VideoFilterOptions Scale(VideoSize videoSize)
|
||||||
public VideoFilterOptions Scale(int width, int height) => WithArgument(new ScaleArgument(width, height));
|
{
|
||||||
public VideoFilterOptions Scale(Size size) => WithArgument(new ScaleArgument(size));
|
return WithArgument(new ScaleArgument(videoSize));
|
||||||
public VideoFilterOptions Transpose(Transposition transposition) => WithArgument(new TransposeArgument(transposition));
|
}
|
||||||
public VideoFilterOptions Mirror(Mirroring mirroring) => WithArgument(new SetMirroringArgument(mirroring));
|
|
||||||
public VideoFilterOptions DrawText(DrawTextOptions drawTextOptions) => WithArgument(new DrawTextArgument(drawTextOptions));
|
public VideoFilterOptions Scale(int width, int height)
|
||||||
public VideoFilterOptions HardBurnSubtitle(SubtitleHardBurnOptions subtitleHardBurnOptions) => WithArgument(new SubtitleHardBurnArgument(subtitleHardBurnOptions));
|
{
|
||||||
public VideoFilterOptions BlackDetect(double minimumDuration = 2.0, double pictureBlackRatioThreshold = 0.98, double pixelBlackThreshold = 0.1) => WithArgument(new BlackDetectArgument(minimumDuration, pictureBlackRatioThreshold, pixelBlackThreshold));
|
return WithArgument(new ScaleArgument(width, height));
|
||||||
public VideoFilterOptions BlackFrame(int amount = 98, int threshold = 32) => WithArgument(new BlackFrameArgument(amount, threshold));
|
}
|
||||||
public VideoFilterOptions Pad(PadOptions padOptions) => WithArgument(new PadArgument(padOptions));
|
|
||||||
|
public VideoFilterOptions Scale(Size size)
|
||||||
|
{
|
||||||
|
return WithArgument(new ScaleArgument(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoFilterOptions Transpose(Transposition transposition)
|
||||||
|
{
|
||||||
|
return WithArgument(new TransposeArgument(transposition));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoFilterOptions Mirror(Mirroring mirroring)
|
||||||
|
{
|
||||||
|
return WithArgument(new SetMirroringArgument(mirroring));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoFilterOptions DrawText(DrawTextOptions drawTextOptions)
|
||||||
|
{
|
||||||
|
return WithArgument(new DrawTextArgument(drawTextOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoFilterOptions HardBurnSubtitle(SubtitleHardBurnOptions subtitleHardBurnOptions)
|
||||||
|
{
|
||||||
|
return WithArgument(new SubtitleHardBurnArgument(subtitleHardBurnOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoFilterOptions BlackDetect(double minimumDuration = 2.0, double pictureBlackRatioThreshold = 0.98, double pixelBlackThreshold = 0.1)
|
||||||
|
{
|
||||||
|
return WithArgument(new BlackDetectArgument(minimumDuration, pictureBlackRatioThreshold, pixelBlackThreshold));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoFilterOptions BlackFrame(int amount = 98, int threshold = 32)
|
||||||
|
{
|
||||||
|
return WithArgument(new BlackFrameArgument(amount, threshold));
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoFilterOptions Pad(PadOptions padOptions)
|
||||||
|
{
|
||||||
|
return WithArgument(new PadArgument(padOptions));
|
||||||
|
}
|
||||||
|
|
||||||
private VideoFilterOptions WithArgument(IVideoFilterArgument argument)
|
private VideoFilterOptions WithArgument(IVideoFilterArgument argument)
|
||||||
{
|
{
|
||||||
Arguments.Add(argument);
|
Arguments.Add(argument);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,17 @@
|
||||||
namespace FFMpegCore.Builders.MetaData
|
namespace FFMpegCore.Builders.MetaData;
|
||||||
|
|
||||||
|
public class ChapterData
|
||||||
{
|
{
|
||||||
public class ChapterData
|
|
||||||
{
|
|
||||||
public string Title { get; private set; }
|
|
||||||
public TimeSpan Start { get; private set; }
|
|
||||||
public TimeSpan End { get; private set; }
|
|
||||||
|
|
||||||
public TimeSpan Duration => End - Start;
|
|
||||||
|
|
||||||
public ChapterData(string title, TimeSpan start, TimeSpan end)
|
public ChapterData(string title, TimeSpan start, TimeSpan end)
|
||||||
{
|
{
|
||||||
Title = title;
|
Title = title;
|
||||||
Start = start;
|
Start = start;
|
||||||
End = end;
|
End = end;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public string Title { get; private set; }
|
||||||
|
public TimeSpan Start { get; }
|
||||||
|
public TimeSpan End { get; }
|
||||||
|
|
||||||
|
public TimeSpan Duration => End - Start;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
namespace FFMpegCore.Builders.MetaData
|
namespace FFMpegCore.Builders.MetaData;
|
||||||
{
|
|
||||||
|
|
||||||
public interface IReadOnlyMetaData
|
public interface IReadOnlyMetaData
|
||||||
{
|
{
|
||||||
IReadOnlyList<ChapterData> Chapters { get; }
|
IReadOnlyList<ChapterData> Chapters { get; }
|
||||||
IReadOnlyDictionary<string, string> Entries { get; }
|
IReadOnlyDictionary<string, string> Entries { get; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,7 @@
|
||||||
namespace FFMpegCore.Builders.MetaData
|
namespace FFMpegCore.Builders.MetaData;
|
||||||
|
|
||||||
|
public class MetaData : IReadOnlyMetaData
|
||||||
{
|
{
|
||||||
public class MetaData : IReadOnlyMetaData
|
|
||||||
{
|
|
||||||
public Dictionary<string, string> Entries { get; private set; }
|
|
||||||
public List<ChapterData> Chapters { get; private set; }
|
|
||||||
|
|
||||||
IReadOnlyList<ChapterData> IReadOnlyMetaData.Chapters => Chapters;
|
|
||||||
IReadOnlyDictionary<string, string> IReadOnlyMetaData.Entries => Entries;
|
|
||||||
|
|
||||||
public MetaData()
|
public MetaData()
|
||||||
{
|
{
|
||||||
Entries = new Dictionary<string, string>();
|
Entries = new Dictionary<string, string>();
|
||||||
|
|
@ -26,5 +20,10 @@
|
||||||
))
|
))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public Dictionary<string, string> Entries { get; }
|
||||||
|
public List<ChapterData> Chapters { get; }
|
||||||
|
|
||||||
|
IReadOnlyList<ChapterData> IReadOnlyMetaData.Chapters => Chapters;
|
||||||
|
IReadOnlyDictionary<string, string> IReadOnlyMetaData.Entries => Entries;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
namespace FFMpegCore.Builders.MetaData
|
namespace FFMpegCore.Builders.MetaData;
|
||||||
|
|
||||||
|
public class MetaDataBuilder
|
||||||
{
|
{
|
||||||
public class MetaDataBuilder
|
|
||||||
{
|
|
||||||
private readonly MetaData _metaData = new();
|
private readonly MetaData _metaData = new();
|
||||||
|
|
||||||
public MetaDataBuilder WithEntry(string key, string entry)
|
public MetaDataBuilder WithEntry(string key, string entry)
|
||||||
|
|
@ -16,10 +16,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
public MetaDataBuilder WithEntry(string key, params string[] values)
|
public MetaDataBuilder WithEntry(string key, params string[] values)
|
||||||
=> WithEntry(key, string.Join("; ", values));
|
{
|
||||||
|
return WithEntry(key, string.Join("; ", values));
|
||||||
|
}
|
||||||
|
|
||||||
public MetaDataBuilder WithEntry(string key, IEnumerable<string> values)
|
public MetaDataBuilder WithEntry(string key, IEnumerable<string> values)
|
||||||
=> WithEntry(key, string.Join("; ", values));
|
{
|
||||||
|
return WithEntry(key, string.Join("; ", values));
|
||||||
|
}
|
||||||
|
|
||||||
public MetaDataBuilder AddChapter(ChapterData chapterData)
|
public MetaDataBuilder AddChapter(ChapterData chapterData)
|
||||||
{
|
{
|
||||||
|
|
@ -55,49 +59,110 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
//major_brand=M4A
|
//major_brand=M4A
|
||||||
public MetaDataBuilder WithMajorBrand(string value) => WithEntry("major_brand", value);
|
public MetaDataBuilder WithMajorBrand(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("major_brand", value);
|
||||||
|
}
|
||||||
|
|
||||||
//minor_version=512
|
//minor_version=512
|
||||||
public MetaDataBuilder WithMinorVersion(string value) => WithEntry("minor_version", value);
|
public MetaDataBuilder WithMinorVersion(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("minor_version", value);
|
||||||
|
}
|
||||||
|
|
||||||
//compatible_brands=M4A isomiso2
|
//compatible_brands=M4A isomiso2
|
||||||
public MetaDataBuilder WithCompatibleBrands(string value) => WithEntry("compatible_brands", value);
|
public MetaDataBuilder WithCompatibleBrands(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("compatible_brands", value);
|
||||||
|
}
|
||||||
|
|
||||||
//copyright=©2017 / 2019 Dennis E. Taylor / Random House Audio / Wilhelm Heyne Verlag. Übersetzung von Urban Hofstetter (P)2019 Random House Audio
|
//copyright=©2017 / 2019 Dennis E. Taylor / Random House Audio / Wilhelm Heyne Verlag. Übersetzung von Urban Hofstetter (P)2019 Random House Audio
|
||||||
public MetaDataBuilder WithCopyright(string value) => WithEntry("copyright", value);
|
public MetaDataBuilder WithCopyright(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("copyright", value);
|
||||||
|
}
|
||||||
|
|
||||||
//title=Alle diese Welten: Bobiverse 3
|
//title=Alle diese Welten: Bobiverse 3
|
||||||
public MetaDataBuilder WithTitle(string value) => WithEntry("title", value);
|
public MetaDataBuilder WithTitle(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("title", value);
|
||||||
|
}
|
||||||
|
|
||||||
//artist=Dennis E. Taylor
|
//artist=Dennis E. Taylor
|
||||||
public MetaDataBuilder WithArtists(params string[] value) => WithEntry("artist", value);
|
public MetaDataBuilder WithArtists(params string[] value)
|
||||||
public MetaDataBuilder WithArtists(IEnumerable<string> value) => WithEntry("artist", value);
|
{
|
||||||
|
return WithEntry("artist", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaDataBuilder WithArtists(IEnumerable<string> value)
|
||||||
|
{
|
||||||
|
return WithEntry("artist", value);
|
||||||
|
}
|
||||||
|
|
||||||
//composer=J. K. Rowling
|
//composer=J. K. Rowling
|
||||||
public MetaDataBuilder WithComposers(params string[] value) => WithEntry("composer", value);
|
public MetaDataBuilder WithComposers(params string[] value)
|
||||||
public MetaDataBuilder WithComposers(IEnumerable<string> value) => WithEntry("composer", value);
|
{
|
||||||
|
return WithEntry("composer", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaDataBuilder WithComposers(IEnumerable<string> value)
|
||||||
|
{
|
||||||
|
return WithEntry("composer", value);
|
||||||
|
}
|
||||||
|
|
||||||
//album_artist=Dennis E. Taylor
|
//album_artist=Dennis E. Taylor
|
||||||
public MetaDataBuilder WithAlbumArtists(params string[] value) => WithEntry("album_artist", value);
|
public MetaDataBuilder WithAlbumArtists(params string[] value)
|
||||||
public MetaDataBuilder WithAlbumArtists(IEnumerable<string> value) => WithEntry("album_artist", value);
|
{
|
||||||
|
return WithEntry("album_artist", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaDataBuilder WithAlbumArtists(IEnumerable<string> value)
|
||||||
|
{
|
||||||
|
return WithEntry("album_artist", value);
|
||||||
|
}
|
||||||
|
|
||||||
//album=Alle diese Welten: Bobiverse 3
|
//album=Alle diese Welten: Bobiverse 3
|
||||||
public MetaDataBuilder WithAlbum(string value) => WithEntry("album", value);
|
public MetaDataBuilder WithAlbum(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("album", value);
|
||||||
|
}
|
||||||
|
|
||||||
//date=2019
|
//date=2019
|
||||||
public MetaDataBuilder WithDate(string value) => WithEntry("date", value);
|
public MetaDataBuilder WithDate(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("date", value);
|
||||||
|
}
|
||||||
|
|
||||||
//genre=Hörbuch
|
//genre=Hörbuch
|
||||||
public MetaDataBuilder WithGenres(params string[] value) => WithEntry("genre", value);
|
public MetaDataBuilder WithGenres(params string[] value)
|
||||||
public MetaDataBuilder WithGenres(IEnumerable<string> value) => WithEntry("genre", value);
|
{
|
||||||
|
return WithEntry("genre", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaDataBuilder WithGenres(IEnumerable<string> value)
|
||||||
|
{
|
||||||
|
return WithEntry("genre", value);
|
||||||
|
}
|
||||||
|
|
||||||
//comment=Chapter 200
|
//comment=Chapter 200
|
||||||
public MetaDataBuilder WithComments(params string[] value) => WithEntry("comment", value);
|
public MetaDataBuilder WithComments(params string[] value)
|
||||||
public MetaDataBuilder WithComments(IEnumerable<string> value) => WithEntry("comment", value);
|
{
|
||||||
|
return WithEntry("comment", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetaDataBuilder WithComments(IEnumerable<string> value)
|
||||||
|
{
|
||||||
|
return WithEntry("comment", value);
|
||||||
|
}
|
||||||
|
|
||||||
//encoder=Lavf58.47.100
|
//encoder=Lavf58.47.100
|
||||||
public MetaDataBuilder WithEncoder(string value) => WithEntry("encoder", value);
|
public MetaDataBuilder WithEncoder(string value)
|
||||||
|
{
|
||||||
|
return WithEntry("encoder", value);
|
||||||
|
}
|
||||||
|
|
||||||
public ReadOnlyMetaData Build() => new(_metaData);
|
public ReadOnlyMetaData Build()
|
||||||
|
{
|
||||||
|
return new ReadOnlyMetaData(_metaData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue