Fix tests

This commit is contained in:
Malte Rosenbjerg 2021-03-06 21:25:17 +01:00
parent 8452672ee6
commit e49290b217
8 changed files with 73 additions and 81 deletions

View file

@ -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);
} }

View file

@ -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);

View file

@ -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}";
} }
} }

View file

@ -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()
{ {

View file

@ -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()

View file

@ -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));

View file

@ -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));
} }

View file

@ -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>