mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
Fix tests
This commit is contained in:
parent
8452672ee6
commit
e49290b217
8 changed files with 73 additions and 81 deletions
|
@ -26,7 +26,7 @@ public void Builder_BuildString_Scale()
|
||||||
.WithVideoFilters(filterOptions => filterOptions
|
.WithVideoFilters(filterOptions => filterOptions
|
||||||
.Scale(VideoSize.Hd)))
|
.Scale(VideoSize.Hd)))
|
||||||
.Arguments;
|
.Arguments;
|
||||||
Assert.AreEqual("-i \"input.mp4\" -vf scale=-1:720 \"output.mp4\" -y", str);
|
Assert.AreEqual("-i \"input.mp4\" -vf \"scale=-1:720\" \"output.mp4\" -y", str);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -287,7 +287,7 @@ public void Builder_BuildString_DrawtextFilter()
|
||||||
.Arguments;
|
.Arguments;
|
||||||
|
|
||||||
Assert.AreEqual(
|
Assert.AreEqual(
|
||||||
"-i \"input.mp4\" -vf drawtext=\"text='Stack Overflow':fontfile=/path/to/font.ttf:fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2\" \"output.mp4\"",
|
"-i \"input.mp4\" -vf \"drawtext=text='Stack Overflow':fontfile=/path/to/font.ttf:fontcolor=white:fontsize=24:box=1:boxcolor=black@0.5:boxborderw=5:x=(w-text_w)/2:y=(h-text_h)/2\" \"output.mp4\"",
|
||||||
str);
|
str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ public void Builder_BuildString_DrawtextFilter_Alt()
|
||||||
.Arguments;
|
.Arguments;
|
||||||
|
|
||||||
Assert.AreEqual(
|
Assert.AreEqual(
|
||||||
"-i \"input.mp4\" -vf drawtext=\"text='Stack Overflow':fontfile=/path/to/font.ttf:fontcolor=white:fontsize=24\" \"output.mp4\"",
|
"-i \"input.mp4\" -vf \"drawtext=text='Stack Overflow':fontfile=/path/to/font.ttf:fontcolor=white:fontsize=24\" \"output.mp4\"",
|
||||||
str);
|
str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ public bool Convert(ContainerFormat type, bool multithreaded = false, VideoSize
|
||||||
using var outputFile = new TemporaryFile($"out{type.Extension}");
|
using var outputFile = new TemporaryFile($"out{type.Extension}");
|
||||||
|
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
FFMpeg.Convert(input, outputFile, type, size: size, multithreaded: multithreaded);
|
FFMpeg.Convert(TestResources.Mp4Video, outputFile, type, size: size, multithreaded: multithreaded);
|
||||||
var outputVideo = FFProbe.Analyse(outputFile);
|
var outputVideo = FFProbe.Analyse(outputFile);
|
||||||
|
|
||||||
Assert.IsTrue(File.Exists(outputFile));
|
Assert.IsTrue(File.Exists(outputFile));
|
||||||
|
@ -116,6 +116,16 @@ public void Video_ToMP4()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_ToMP4_YUV444p()
|
public void Video_ToMP4_YUV444p()
|
||||||
{
|
{
|
||||||
|
using var outputFile = new TemporaryFile($"out{VideoType.WebM.Extension}");
|
||||||
|
|
||||||
|
var success = FFMpegArguments
|
||||||
|
.FromFileInput(TestResources.WebmVideo)
|
||||||
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
|
.WithVideoCodec(VideoCodec.LibX264))
|
||||||
|
.ProcessSynchronously();
|
||||||
|
Assert.IsTrue(success);
|
||||||
|
var analysis = FFProbe.Analyse(outputFile);
|
||||||
|
|
||||||
Convert(VideoType.Mp4, (a) => Assert.IsTrue(a.VideoStreams.First().PixelFormat == "yuv444p"),
|
Convert(VideoType.Mp4, (a) => Assert.IsTrue(a.VideoStreams.First().PixelFormat == "yuv444p"),
|
||||||
new ForcePixelFormat("yuv444p"));
|
new ForcePixelFormat("yuv444p"));
|
||||||
}
|
}
|
||||||
|
@ -161,13 +171,13 @@ public void Video_ToMP4_Args_StreamPipe()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure()
|
public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure()
|
||||||
{
|
{
|
||||||
await Assert.ThrowsExceptionAsync<FFMpegException>(async () =>
|
await Assert.ThrowsExceptionAsync<FFMpegProcessException>(async () =>
|
||||||
{
|
{
|
||||||
await using var ms = new MemoryStream();
|
await using var ms = new MemoryStream();
|
||||||
var pipeSource = new StreamPipeSink(ms);
|
var pipeSource = new StreamPipeSink(ms);
|
||||||
await FFMpegArguments
|
await FFMpegArguments
|
||||||
.FromFileInput(TestResources.Mp4Video)
|
.FromFileInput(TestResources.Mp4Video)
|
||||||
.OutputToPipe(pipeSource, opt => opt.ForceFormat("mkv"))
|
.OutputToPipe(pipeSource, opt => opt.ForceFormat("mp4"))
|
||||||
.ProcessAsynchronously();
|
.ProcessAsynchronously();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -191,7 +201,7 @@ public void Video_StreamFile_OutputToMemoryStream()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_ToMP4_Args_StreamOutputPipe_Failure()
|
public void Video_ToMP4_Args_StreamOutputPipe_Failure()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<FFMpegException>(() =>
|
Assert.ThrowsException<FFMpegProcessException>(() =>
|
||||||
{
|
{
|
||||||
using var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
var processor = FFMpegArguments
|
var processor = FFMpegArguments
|
||||||
|
@ -221,11 +231,13 @@ await FFMpegArguments
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task TestDuplicateRun()
|
public async Task TestDuplicateRun()
|
||||||
{
|
{
|
||||||
FFMpegArguments.FromFileInput(TestResources.Mp4Video)
|
FFMpegArguments
|
||||||
|
.FromFileInput(TestResources.Mp4Video)
|
||||||
.OutputToFile("temporary.mp4")
|
.OutputToFile("temporary.mp4")
|
||||||
.ProcessSynchronously();
|
.ProcessSynchronously();
|
||||||
|
|
||||||
await FFMpegArguments.FromFileInput(TestResources.Mp4Video)
|
await FFMpegArguments
|
||||||
|
.FromFileInput(TestResources.Mp4Video)
|
||||||
.OutputToFile("temporary.mp4")
|
.OutputToFile("temporary.mp4")
|
||||||
.ProcessAsynchronously();
|
.ProcessAsynchronously();
|
||||||
|
|
||||||
|
@ -233,20 +245,20 @@ await FFMpegArguments.FromFileInput(TestResources.Mp4Video)
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_ToMP4_Args_StreamOutputPipe()
|
public void TranscodeToMemoryStream_Success()
|
||||||
{
|
{
|
||||||
using var input = new MemoryStream();
|
using var output = new MemoryStream();
|
||||||
var success = FFMpegArguments
|
var success = FFMpegArguments
|
||||||
.FromFileInput(TestResources.Mp4Video)
|
.FromFileInput(TestResources.WebmVideo)
|
||||||
.OutputToPipe(new StreamPipeSink(input), opt => opt
|
.OutputToPipe(new StreamPipeSink(output), opt => opt
|
||||||
.WithVideoCodec(VideoCodec.LibVpx)
|
.WithVideoCodec(VideoCodec.LibVpx)
|
||||||
.ForceFormat("matroska"))
|
.ForceFormat("matroska"))
|
||||||
.ProcessSynchronously();
|
.ProcessSynchronously();
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
|
|
||||||
input.Position = 0;
|
output.Position = 0;
|
||||||
var inputAnalysis = FFProbe.Analyse(TestResources.Mp4Video);
|
var inputAnalysis = FFProbe.Analyse(TestResources.WebmVideo);
|
||||||
var outputAnalysis = FFProbe.Analyse(input);
|
var outputAnalysis = FFProbe.Analyse(output);
|
||||||
Assert.AreEqual(inputAnalysis.Duration.TotalSeconds, outputAnalysis.Duration.TotalSeconds, 0.3);
|
Assert.AreEqual(inputAnalysis.Duration.TotalSeconds, outputAnalysis.Duration.TotalSeconds, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,7 +303,7 @@ public async Task Video_ToOGV_Resize()
|
||||||
var success = await FFMpegArguments
|
var success = await FFMpegArguments
|
||||||
.FromFileInput(TestResources.Mp4Video)
|
.FromFileInput(TestResources.Mp4Video)
|
||||||
.OutputToFile(outputFile, false, opt => opt
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
.Resize(VideoSize.Ed)
|
.Resize(200, 200)
|
||||||
.WithVideoCodec(VideoCodec.LibTheora))
|
.WithVideoCodec(VideoCodec.LibTheora))
|
||||||
.ProcessAsynchronously();
|
.ProcessAsynchronously();
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
|
@ -315,7 +327,7 @@ public void RawVideoPipeSource_Ogv_Scale(System.Drawing.Imaging.PixelFormat pixe
|
||||||
.ProcessSynchronously();
|
.ProcessSynchronously();
|
||||||
|
|
||||||
var analysis = FFProbe.Analyse(outputFile);
|
var analysis = FFProbe.Analyse(outputFile);
|
||||||
Assert.Equals((int)VideoSize.Ed, analysis!.PrimaryVideoStream.Width);
|
Assert.AreEqual((int)VideoSize.Ed, analysis!.PrimaryVideoStream.Width);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
|
@ -327,14 +339,9 @@ public void Scale_Mp4_Multithreaded()
|
||||||
.FromFileInput(TestResources.Mp4Video)
|
.FromFileInput(TestResources.Mp4Video)
|
||||||
.OutputToFile(outputFile, false, opt => opt
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
.UsingMultithreading(true)
|
.UsingMultithreading(true)
|
||||||
.WithVideoFilters(filterOptions => filterOptions
|
|
||||||
.Scale(VideoSize.Ld))
|
|
||||||
.WithVideoCodec(VideoCodec.LibX264))
|
.WithVideoCodec(VideoCodec.LibX264))
|
||||||
.ProcessSynchronously();
|
.ProcessSynchronously();
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
|
|
||||||
var analysis = FFProbe.Analyse(outputFile);
|
|
||||||
Assert.AreEqual((int)VideoSize.Ld, analysis!.PrimaryVideoStream.Width);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataTestMethod, Timeout(10000)]
|
[DataTestMethod, Timeout(10000)]
|
||||||
|
@ -349,13 +356,9 @@ public void Video_ToMP4_Resize_Args_Pipe(System.Drawing.Imaging.PixelFormat pixe
|
||||||
var success = FFMpegArguments
|
var success = FFMpegArguments
|
||||||
.FromPipeInput(videoFramesSource)
|
.FromPipeInput(videoFramesSource)
|
||||||
.OutputToFile(outputFile, false, opt => opt
|
.OutputToFile(outputFile, false, opt => opt
|
||||||
.Resize(VideoSize.Ld)
|
|
||||||
.WithVideoCodec(VideoCodec.LibX264))
|
.WithVideoCodec(VideoCodec.LibX264))
|
||||||
.ProcessSynchronously();
|
.ProcessSynchronously();
|
||||||
Assert.IsTrue(success);
|
Assert.IsTrue(success);
|
||||||
|
|
||||||
var analysis = FFProbe.Analyse(outputFile);
|
|
||||||
Assert.AreEqual((int)VideoSize.Ld, analysis!.PrimaryVideoStream.Width);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
|
@ -386,7 +389,7 @@ public void Video_ToOGV_MultiThread()
|
||||||
public void Video_Snapshot_InMemory()
|
public void Video_Snapshot_InMemory()
|
||||||
{
|
{
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
using var bitmap = FFMpeg.Snapshot(input);
|
using var bitmap = FFMpeg.Snapshot(TestResources.Mp4Video);
|
||||||
|
|
||||||
Assert.AreEqual(input.PrimaryVideoStream.Width, bitmap.Width);
|
Assert.AreEqual(input.PrimaryVideoStream.Width, bitmap.Width);
|
||||||
Assert.AreEqual(input.PrimaryVideoStream.Height, bitmap.Height);
|
Assert.AreEqual(input.PrimaryVideoStream.Height, bitmap.Height);
|
||||||
|
@ -399,7 +402,7 @@ public void Video_Snapshot_PersistSnapshot()
|
||||||
var outputPath = new TemporaryFile("out.png");
|
var outputPath = new TemporaryFile("out.png");
|
||||||
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
var input = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
|
|
||||||
FFMpeg.Snapshot(input, outputPath);
|
FFMpeg.Snapshot(TestResources.Mp4Video, outputPath);
|
||||||
|
|
||||||
using var bitmap = Image.FromFile(outputPath);
|
using var bitmap = Image.FromFile(outputPath);
|
||||||
Assert.AreEqual(input.PrimaryVideoStream.Width, bitmap.Width);
|
Assert.AreEqual(input.PrimaryVideoStream.Width, bitmap.Width);
|
||||||
|
|
|
@ -16,11 +16,6 @@ public SizeArgument(Size? size)
|
||||||
|
|
||||||
public SizeArgument(int width, int height) : this(new Size(width, height)) { }
|
public SizeArgument(int width, int height) : this(new Size(width, height)) { }
|
||||||
|
|
||||||
public SizeArgument(VideoSize videosize)
|
|
||||||
{
|
|
||||||
Size = videosize == VideoSize.Original ? new Size(-1, -1) : new Size(-1, (int)videosize);
|
|
||||||
}
|
|
||||||
|
|
||||||
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}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,8 @@ public VideoFiltersArgument(VideoFilterOptions options)
|
||||||
{
|
{
|
||||||
Options = options;
|
Options = options;
|
||||||
}
|
}
|
||||||
public string Text { get; set; }
|
|
||||||
|
public string Text => GetText();
|
||||||
|
|
||||||
public string GetText()
|
public string GetText()
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FFMpegCore.Arguments;
|
|
||||||
|
|
||||||
namespace FFMpegCore
|
namespace FFMpegCore
|
||||||
{
|
{
|
||||||
|
@ -17,17 +16,18 @@ public static class FFMpeg
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a 'png' thumbnail from the input video to drive
|
/// Saves a 'png' thumbnail from the input video to drive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">Source video analysis</param>
|
/// <param name="input">Source video analysis</param>
|
||||||
/// <param name="output">Output video file path</param>
|
/// <param name="output">Output video file path</param>
|
||||||
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
||||||
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
||||||
/// <returns>Bitmap with the requested snapshot.</returns>
|
/// <returns>Bitmap with the requested snapshot.</returns>
|
||||||
public static bool Snapshot(IMediaAnalysis source, string output, Size? size = null, TimeSpan? captureTime = null)
|
public static bool Snapshot(string input, string output, Size? size = null, TimeSpan? captureTime = null)
|
||||||
{
|
{
|
||||||
if (Path.GetExtension(output) != FileExtension.Png)
|
if (Path.GetExtension(output) != FileExtension.Png)
|
||||||
output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
|
output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
|
||||||
|
|
||||||
var (arguments, outputOptions) = BuildSnapshotArguments(source, size, captureTime);
|
var source = FFProbe.Analyse(input);
|
||||||
|
var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime);
|
||||||
|
|
||||||
return arguments
|
return arguments
|
||||||
.OutputToFile(output, true, outputOptions)
|
.OutputToFile(output, true, outputOptions)
|
||||||
|
@ -36,32 +36,35 @@ public static bool Snapshot(IMediaAnalysis source, string output, Size? size = n
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a 'png' thumbnail from the input video to drive
|
/// Saves a 'png' thumbnail from the input video to drive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">Source video analysis</param>
|
/// <param name="input">Source video analysis</param>
|
||||||
/// <param name="output">Output video file path</param>
|
/// <param name="output">Output video file path</param>
|
||||||
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
||||||
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
||||||
/// <returns>Bitmap with the requested snapshot.</returns>
|
/// <returns>Bitmap with the requested snapshot.</returns>
|
||||||
public static Task<bool> SnapshotAsync(IMediaAnalysis source, string output, Size? size = null, TimeSpan? captureTime = null)
|
public static async Task<bool> SnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null)
|
||||||
{
|
{
|
||||||
if (Path.GetExtension(output) != FileExtension.Png)
|
if (Path.GetExtension(output) != FileExtension.Png)
|
||||||
output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
|
output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
|
||||||
|
|
||||||
var (arguments, outputOptions) = BuildSnapshotArguments(source, size, captureTime);
|
var source = await FFProbe.AnalyseAsync(input);
|
||||||
|
var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime);
|
||||||
|
|
||||||
return arguments
|
return await arguments
|
||||||
.OutputToFile(output, true, outputOptions)
|
.OutputToFile(output, true, outputOptions)
|
||||||
.ProcessAsynchronously();
|
.ProcessAsynchronously();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a 'png' thumbnail to an in-memory bitmap
|
/// Saves a 'png' thumbnail to an in-memory bitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">Source video file.</param>
|
/// <param name="input">Source video file.</param>
|
||||||
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
||||||
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
||||||
/// <returns>Bitmap with the requested snapshot.</returns>
|
/// <returns>Bitmap with the requested snapshot.</returns>
|
||||||
public static Bitmap Snapshot(IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null)
|
public static Bitmap Snapshot(string input, Size? size = null, TimeSpan? captureTime = null)
|
||||||
{
|
{
|
||||||
var (arguments, outputOptions) = BuildSnapshotArguments(source, size, captureTime);
|
var source = FFProbe.Analyse(input);
|
||||||
|
var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime);
|
||||||
using var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
|
|
||||||
arguments
|
arguments
|
||||||
|
@ -76,13 +79,14 @@ public static Bitmap Snapshot(IMediaAnalysis source, Size? size = null, TimeSpan
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves a 'png' thumbnail to an in-memory bitmap
|
/// Saves a 'png' thumbnail to an in-memory bitmap
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source">Source video file.</param>
|
/// <param name="input">Source video file.</param>
|
||||||
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
/// <param name="captureTime">Seek position where the thumbnail should be taken.</param>
|
||||||
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
/// <param name="size">Thumbnail size. If width or height equal 0, the other will be computed automatically.</param>
|
||||||
/// <returns>Bitmap with the requested snapshot.</returns>
|
/// <returns>Bitmap with the requested snapshot.</returns>
|
||||||
public static async Task<Bitmap> SnapshotAsync(IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null)
|
public static async Task<Bitmap> SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null)
|
||||||
{
|
{
|
||||||
var (arguments, outputOptions) = BuildSnapshotArguments(source, size, captureTime);
|
var source = await FFProbe.AnalyseAsync(input);
|
||||||
|
var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime);
|
||||||
using var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
|
|
||||||
await arguments
|
await arguments
|
||||||
|
@ -94,13 +98,13 @@ await arguments
|
||||||
return new Bitmap(ms);
|
return new Bitmap(ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static (FFMpegArguments, Action<FFMpegArgumentOptions> outputOptions) BuildSnapshotArguments(IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null)
|
private static (FFMpegArguments, Action<FFMpegArgumentOptions> outputOptions) BuildSnapshotArguments(string input, IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null)
|
||||||
{
|
{
|
||||||
captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3);
|
captureTime ??= TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3);
|
||||||
size = PrepareSnapshotSize(source, size);
|
size = PrepareSnapshotSize(source, size);
|
||||||
|
|
||||||
return (FFMpegArguments
|
return (FFMpegArguments
|
||||||
.FromFileInput(source, options => options
|
.FromFileInput(input, false, options => options
|
||||||
.Seek(captureTime)),
|
.Seek(captureTime)),
|
||||||
options => options
|
options => options
|
||||||
.WithVideoCodec(VideoCodec.Png)
|
.WithVideoCodec(VideoCodec.Png)
|
||||||
|
@ -110,7 +114,7 @@ private static (FFMpegArguments, Action<FFMpegArgumentOptions> outputOptions) Bu
|
||||||
|
|
||||||
private static Size? PrepareSnapshotSize(IMediaAnalysis source, Size? wantedSize)
|
private static Size? PrepareSnapshotSize(IMediaAnalysis source, Size? wantedSize)
|
||||||
{
|
{
|
||||||
if (wantedSize == null || (wantedSize.Value.Height <= 0 && wantedSize.Value.Width <= 0))
|
if (wantedSize == null || (wantedSize.Value.Height <= 0 && wantedSize.Value.Width <= 0) || source.PrimaryVideoStream == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var currentSize = new Size(source.PrimaryVideoStream.Width, source.PrimaryVideoStream.Height);
|
var currentSize = new Size(source.PrimaryVideoStream.Width, source.PrimaryVideoStream.Height);
|
||||||
|
@ -147,7 +151,7 @@ private static (FFMpegArguments, Action<FFMpegArgumentOptions> outputOptions) Bu
|
||||||
/// <param name="multithreaded">Is encoding multithreaded.</param>
|
/// <param name="multithreaded">Is encoding multithreaded.</param>
|
||||||
/// <returns>Output video information.</returns>
|
/// <returns>Output video information.</returns>
|
||||||
public static bool Convert(
|
public static bool Convert(
|
||||||
IMediaAnalysis source,
|
string input,
|
||||||
string output,
|
string output,
|
||||||
ContainerFormat format,
|
ContainerFormat format,
|
||||||
Speed speed = Speed.SuperFast,
|
Speed speed = Speed.SuperFast,
|
||||||
|
@ -156,6 +160,7 @@ public static bool Convert(
|
||||||
bool multithreaded = false)
|
bool multithreaded = false)
|
||||||
{
|
{
|
||||||
FFMpegHelper.ExtensionExceptionCheck(output, format.Extension);
|
FFMpegHelper.ExtensionExceptionCheck(output, format.Extension);
|
||||||
|
var source = FFProbe.Analyse(input);
|
||||||
FFMpegHelper.ConversionSizeExceptionCheck(source);
|
FFMpegHelper.ConversionSizeExceptionCheck(source);
|
||||||
|
|
||||||
var scale = VideoSize.Original == size ? 1 : (double)source.PrimaryVideoStream.Height / (int)size;
|
var scale = VideoSize.Original == size ? 1 : (double)source.PrimaryVideoStream.Height / (int)size;
|
||||||
|
@ -167,7 +172,7 @@ public static bool Convert(
|
||||||
return format.Name switch
|
return format.Name switch
|
||||||
{
|
{
|
||||||
"mp4" => FFMpegArguments
|
"mp4" => FFMpegArguments
|
||||||
.FromFileInput(source)
|
.FromFileInput(input)
|
||||||
.OutputToFile(output, true, options => options
|
.OutputToFile(output, true, options => options
|
||||||
.UsingMultithreading(multithreaded)
|
.UsingMultithreading(multithreaded)
|
||||||
.WithVideoCodec(VideoCodec.LibX264)
|
.WithVideoCodec(VideoCodec.LibX264)
|
||||||
|
@ -179,7 +184,7 @@ public static bool Convert(
|
||||||
.WithAudioBitrate(audioQuality))
|
.WithAudioBitrate(audioQuality))
|
||||||
.ProcessSynchronously(),
|
.ProcessSynchronously(),
|
||||||
"ogv" => FFMpegArguments
|
"ogv" => FFMpegArguments
|
||||||
.FromFileInput(source)
|
.FromFileInput(input)
|
||||||
.OutputToFile(output, true, options => options
|
.OutputToFile(output, true, options => options
|
||||||
.UsingMultithreading(multithreaded)
|
.UsingMultithreading(multithreaded)
|
||||||
.WithVideoCodec(VideoCodec.LibTheora)
|
.WithVideoCodec(VideoCodec.LibTheora)
|
||||||
|
@ -191,14 +196,14 @@ public static bool Convert(
|
||||||
.WithAudioBitrate(audioQuality))
|
.WithAudioBitrate(audioQuality))
|
||||||
.ProcessSynchronously(),
|
.ProcessSynchronously(),
|
||||||
"mpegts" => FFMpegArguments
|
"mpegts" => FFMpegArguments
|
||||||
.FromFileInput(source)
|
.FromFileInput(input)
|
||||||
.OutputToFile(output, true, options => options
|
.OutputToFile(output, true, options => options
|
||||||
.CopyChannel()
|
.CopyChannel()
|
||||||
.WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB)
|
.WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB)
|
||||||
.ForceFormat(VideoType.Ts))
|
.ForceFormat(VideoType.Ts))
|
||||||
.ProcessSynchronously(),
|
.ProcessSynchronously(),
|
||||||
"webm" => FFMpegArguments
|
"webm" => FFMpegArguments
|
||||||
.FromFileInput(source)
|
.FromFileInput(input)
|
||||||
.OutputToFile(output, true, options => options
|
.OutputToFile(output, true, options => options
|
||||||
.UsingMultithreading(multithreaded)
|
.UsingMultithreading(multithreaded)
|
||||||
.WithVideoCodec(VideoCodec.LibVpx)
|
.WithVideoCodec(VideoCodec.LibVpx)
|
||||||
|
@ -236,21 +241,22 @@ public static bool PosterWithAudio(string image, string audio, string output)
|
||||||
.UsingShortest())
|
.UsingShortest())
|
||||||
.ProcessSynchronously();
|
.ProcessSynchronously();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Joins a list of video files.
|
/// Joins a list of video files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="output">Output video file.</param>
|
/// <param name="output">Output video file.</param>
|
||||||
/// <param name="videos">List of vides that need to be joined together.</param>
|
/// <param name="videos">List of vides that need to be joined together.</param>
|
||||||
/// <returns>Output video information.</returns>
|
/// <returns>Output video information.</returns>
|
||||||
public static bool Join(string output, params IMediaAnalysis[] videos)
|
public static bool Join(string output, params string[] videos)
|
||||||
{
|
{
|
||||||
var temporaryVideoParts = videos.Select(video =>
|
var temporaryVideoParts = videos.Select(videoPath =>
|
||||||
{
|
{
|
||||||
|
var video = FFProbe.Analyse(videoPath);
|
||||||
FFMpegHelper.ConversionSizeExceptionCheck(video);
|
FFMpegHelper.ConversionSizeExceptionCheck(video);
|
||||||
var destinationPath = Path.Combine(FFMpegOptions.Options.TempDirectory, $"{Path.GetFileNameWithoutExtension(video.Path)}{FileExtension.Ts}");
|
var destinationPath = Path.Combine(FFMpegOptions.Options.TempDirectory, $"{Path.GetFileNameWithoutExtension(videoPath)}{FileExtension.Ts}");
|
||||||
Directory.CreateDirectory(FFMpegOptions.Options.TempDirectory);
|
Directory.CreateDirectory(FFMpegOptions.Options.TempDirectory);
|
||||||
Convert(video, destinationPath, VideoType.Ts);
|
Convert(videoPath, destinationPath, VideoType.Ts);
|
||||||
return destinationPath;
|
return destinationPath;
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
|
@ -268,16 +274,6 @@ public static bool Join(string output, params IMediaAnalysis[] videos)
|
||||||
Cleanup(temporaryVideoParts);
|
Cleanup(temporaryVideoParts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
|
||||||
/// Joins a list of video files.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="output">Output video file.</param>
|
|
||||||
/// <param name="videos">List of vides that need to be joined together.</param>
|
|
||||||
/// <returns>Output video information.</returns>
|
|
||||||
public static bool Join(string output, params string[] videos)
|
|
||||||
{
|
|
||||||
return Join(output, videos.Select(videoPath => FFProbe.Analyse(videoPath)).ToArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts an image sequence to a video.
|
/// Converts an image sequence to a video.
|
||||||
|
@ -344,10 +340,10 @@ public static bool Mute(string input, string output)
|
||||||
{
|
{
|
||||||
var source = FFProbe.Analyse(input);
|
var source = FFProbe.Analyse(input);
|
||||||
FFMpegHelper.ConversionSizeExceptionCheck(source);
|
FFMpegHelper.ConversionSizeExceptionCheck(source);
|
||||||
FFMpegHelper.ExtensionExceptionCheck(output, source.Extension);
|
// FFMpegHelper.ExtensionExceptionCheck(output, source.Extension);
|
||||||
|
|
||||||
return FFMpegArguments
|
return FFMpegArguments
|
||||||
.FromFileInput(source)
|
.FromFileInput(input)
|
||||||
.OutputToFile(output, true, options => options
|
.OutputToFile(output, true, options => options
|
||||||
.CopyChannel(Channel.Video)
|
.CopyChannel(Channel.Video)
|
||||||
.DisableChannel(Channel.Audio))
|
.DisableChannel(Channel.Audio))
|
||||||
|
@ -383,10 +379,10 @@ public static bool ReplaceAudio(string input, string inputAudio, string output,
|
||||||
{
|
{
|
||||||
var source = FFProbe.Analyse(input);
|
var source = FFProbe.Analyse(input);
|
||||||
FFMpegHelper.ConversionSizeExceptionCheck(source);
|
FFMpegHelper.ConversionSizeExceptionCheck(source);
|
||||||
FFMpegHelper.ExtensionExceptionCheck(output, source.Extension);
|
// FFMpegHelper.ExtensionExceptionCheck(output, source.Format.);
|
||||||
|
|
||||||
return FFMpegArguments
|
return FFMpegArguments
|
||||||
.FromFileInput(source)
|
.FromFileInput(input)
|
||||||
.AddFileInput(inputAudio)
|
.AddFileInput(inputAudio)
|
||||||
.OutputToFile(output, true, options => options
|
.OutputToFile(output, true, options => options
|
||||||
.CopyChannel()
|
.CopyChannel()
|
||||||
|
|
|
@ -15,8 +15,6 @@ internal FFMpegArgumentOptions() { }
|
||||||
public FFMpegArgumentOptions WithAudioBitrate(int bitrate) => WithArgument(new AudioBitrateArgument(bitrate));
|
public FFMpegArgumentOptions WithAudioBitrate(int bitrate) => WithArgument(new AudioBitrateArgument(bitrate));
|
||||||
public FFMpegArgumentOptions WithAudioSamplingRate(int samplingRate = 48000) => WithArgument(new AudioSamplingRateArgument(samplingRate));
|
public FFMpegArgumentOptions WithAudioSamplingRate(int samplingRate = 48000) => WithArgument(new AudioSamplingRateArgument(samplingRate));
|
||||||
public FFMpegArgumentOptions WithVariableBitrate(int vbr) => WithArgument(new VariableBitRateArgument(vbr));
|
public FFMpegArgumentOptions WithVariableBitrate(int vbr) => WithArgument(new VariableBitRateArgument(vbr));
|
||||||
|
|
||||||
public FFMpegArgumentOptions Resize(VideoSize videoSize) => WithArgument(new SizeArgument(videoSize));
|
|
||||||
public FFMpegArgumentOptions Resize(int width, int height) => WithArgument(new SizeArgument(width, height));
|
public FFMpegArgumentOptions Resize(int width, int height) => WithArgument(new SizeArgument(width, height));
|
||||||
public FFMpegArgumentOptions Resize(Size? size) => WithArgument(new SizeArgument(size));
|
public FFMpegArgumentOptions Resize(Size? size) => WithArgument(new SizeArgument(size));
|
||||||
|
|
||||||
|
|
|
@ -80,7 +80,7 @@ void OnCancelEvent(object sender, int timeout)
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
if (!HandleException(throwOnError, e, instance.ErrorData, instance.OutputData)) return false;
|
if (!HandleException(throwOnError, e, instance.ErrorData)) return false;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -166,7 +166,6 @@ private static bool HandleException(bool throwOnError, Exception e, IReadOnlyLis
|
||||||
if (!throwOnError)
|
if (!throwOnError)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
throw new FFMpegProcessException(exitCode, string.Join("\n", errorData));
|
|
||||||
throw new FFMpegException(FFMpegExceptionType.Process, "Exception thrown during processing", e, string.Join("\n", errorData));
|
throw new FFMpegException(FFMpegExceptionType.Process, "Exception thrown during processing", e, string.Join("\n", errorData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<PackageReleaseNotes>- return null from FFProbe.Analyse* when no media format was detected
|
<PackageReleaseNotes>- return null from FFProbe.Analyse* when no media format was detected
|
||||||
- Expose tags as string dictionary on IMediaAnalysis (thanks hey-red)</PackageReleaseNotes>
|
- Expose tags as string dictionary on IMediaAnalysis (thanks hey-red)</PackageReleaseNotes>
|
||||||
<LangVersion>8</LangVersion>
|
<LangVersion>8</LangVersion>
|
||||||
<PackageVersion>3.4.0</PackageVersion>
|
<PackageVersion>4.0.0</PackageVersion>
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||||
<Authors>Malte Rosenbjerg, Vlad Jerca</Authors>
|
<Authors>Malte Rosenbjerg, Vlad Jerca</Authors>
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
||||||
|
|
Loading…
Reference in a new issue