diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index c470186..c807872 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,9 +23,9 @@ jobs:
uses: actions/checkout@v3
- name: Prepare .NET
- uses: actions/setup-dotnet@v2
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: '6.0.x'
+ dotnet-version: '7.0.x'
- name: Prepare FFMpeg
uses: Iamshankhadeep/setup-ffmpeg@v1.2
@@ -34,4 +34,4 @@ jobs:
version: "4.4"
- name: Test with dotnet
- run: dotnet test --logger GitHubActions
+ run: dotnet test FFMpegCore.sln --logger GitHubActions
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7cf1425..0c7725b 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -8,13 +8,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v2
- - name: Prepare .NET
- uses: actions/setup-dotnet@v1
- with:
- dotnet-version: '6.0.x'
- - name: Build solution
- run: dotnet build --output build -c Release
- - name: Publish NuGet package
- run: dotnet nuget push "build/*.nupkg" --source nuget.org --api-key ${{ secrets.NUGET_TOKEN }}
+ uses: actions/checkout@v3
+
+ - name: Prepare .NET
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '7.0.x'
+
+ - name: Build solution
+ run: dotnet pack FFMpegCore.sln --output build -c Release
+
+ - name: Publish NuGet package
+ run: dotnet nuget push build/*.nupkg --source nuget.org --api-key ${{ secrets.NUGET_TOKEN }}
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..caefd5d
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,15 @@
+
+
+ netstandard2.0
+ en
+ 5.0.0.0
+ default
+ enable
+
+ GitHub
+ https://github.com/rosenbjerg/FFMpegCore
+ https://github.com/rosenbjerg/FFMpegCore
+ MIT
+ en
+
+
\ No newline at end of file
diff --git a/FFMpegCore.Examples/FFMpegCore.Examples.csproj b/FFMpegCore.Examples/FFMpegCore.Examples.csproj
index 68e7b5c..347607f 100644
--- a/FFMpegCore.Examples/FFMpegCore.Examples.csproj
+++ b/FFMpegCore.Examples/FFMpegCore.Examples.csproj
@@ -6,6 +6,7 @@
+
diff --git a/FFMpegCore.Examples/Program.cs b/FFMpegCore.Examples/Program.cs
index a718a21..e7b93e2 100644
--- a/FFMpegCore.Examples/Program.cs
+++ b/FFMpegCore.Examples/Program.cs
@@ -5,7 +5,7 @@
using FFMpegCore;
using FFMpegCore.Enums;
using FFMpegCore.Pipes;
-using FFMpegCore.Extend;
+using FFMpegCore.Extensions.System.Drawing.Common;
var inputPath = "/path/to/input";
var outputPath = "/path/to/output";
@@ -34,7 +34,7 @@
{
// process the snapshot in-memory and use the Bitmap directly
- var bitmap = FFMpeg.Snapshot(inputPath, new Size(200, 400), TimeSpan.FromMinutes(1));
+ var bitmap = FFMpegImage.Snapshot(inputPath, new Size(200, 400), TimeSpan.FromMinutes(1));
// or persists the image on the drive
FFMpeg.Snapshot(inputPath, outputPath, new Size(200, 400), TimeSpan.FromMinutes(1));
@@ -61,7 +61,7 @@ await FFMpegArguments
}
{
- FFMpeg.JoinImageSequence(@"..\joined_video.mp4", frameRate: 1,
+ FFMpegImage.JoinImageSequence(@"..\joined_video.mp4", frameRate: 1,
ImageInfo.FromPath(@"..\1.png"),
ImageInfo.FromPath(@"..\2.png"),
ImageInfo.FromPath(@"..\3.png")
@@ -83,9 +83,9 @@ await FFMpegArguments
var inputImagePath = "/path/to/input/image";
{
- FFMpeg.PosterWithAudio(inputPath, inputAudioPath, outputPath);
- // or
- var image = Image.FromFile(inputImagePath);
+ FFMpegImage.PosterWithAudio(inputPath, inputAudioPath, outputPath);
+ // or
+ using var image = Image.FromFile(inputImagePath);
image.AddAudio(inputAudioPath, outputPath);
}
diff --git a/FFMpegCore/Extend/BitmapExtensions.cs b/FFMpegCore.Extensions.System.Drawing.Common/BitmapExtensions.cs
similarity index 78%
rename from FFMpegCore/Extend/BitmapExtensions.cs
rename to FFMpegCore.Extensions.System.Drawing.Common/BitmapExtensions.cs
index e2f5505..6633f69 100644
--- a/FFMpegCore/Extend/BitmapExtensions.cs
+++ b/FFMpegCore.Extensions.System.Drawing.Common/BitmapExtensions.cs
@@ -2,7 +2,7 @@
using System.Drawing;
using System.IO;
-namespace FFMpegCore.Extend
+namespace FFMpegCore.Extensions.System.Drawing.Common
{
public static class BitmapExtensions
{
@@ -12,7 +12,7 @@ public static bool AddAudio(this Image poster, string audio, string output)
poster.Save(destination);
try
{
- return FFMpeg.PosterWithAudio(destination, audio, output);
+ return FFMpegImage.PosterWithAudio(destination, audio, output);
}
finally
{
diff --git a/FFMpegCore/Extend/BitmapVideoFrameWrapper.cs b/FFMpegCore.Extensions.System.Drawing.Common/BitmapVideoFrameWrapper.cs
similarity index 98%
rename from FFMpegCore/Extend/BitmapVideoFrameWrapper.cs
rename to FFMpegCore.Extensions.System.Drawing.Common/BitmapVideoFrameWrapper.cs
index 2222db6..2259fea 100644
--- a/FFMpegCore/Extend/BitmapVideoFrameWrapper.cs
+++ b/FFMpegCore.Extensions.System.Drawing.Common/BitmapVideoFrameWrapper.cs
@@ -7,7 +7,7 @@
using System.Threading.Tasks;
using FFMpegCore.Pipes;
-namespace FFMpegCore.Extend
+namespace FFMpegCore.Extensions.System.Drawing.Common
{
public class BitmapVideoFrameWrapper : IVideoFrame, IDisposable
{
diff --git a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegCore.Extensions.System.Drawing.Common.csproj b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegCore.Extensions.System.Drawing.Common.csproj
new file mode 100644
index 0000000..aafb577
--- /dev/null
+++ b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegCore.Extensions.System.Drawing.Common.csproj
@@ -0,0 +1,21 @@
+
+
+
+ true
+ Image extension for FFMpegCore using System.Common.Drawing
+ 5.0.0
+
+
+ ffmpeg ffprobe convert video audio mediafile resize analyze muxing
+ Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev
+
+
+
+
+
+
+
+
+
+
+
diff --git a/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs
new file mode 100644
index 0000000..467fe6a
--- /dev/null
+++ b/FFMpegCore.Extensions.System.Drawing.Common/FFMpegImage.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using FFMpegCore.Enums;
+using FFMpegCore.Helpers;
+using FFMpegCore.Pipes;
+
+namespace FFMpegCore.Extensions.System.Drawing.Common
+{
+ public static class FFMpegImage
+ {
+ public static void ConversionSizeExceptionCheck(Image image)
+ => FFMpegHelper.ConversionSizeExceptionCheck(image.Size.Width, image.Size.Height);
+
+ ///
+ /// Converts an image sequence to a video.
+ ///
+ /// Output video file.
+ /// FPS
+ /// Image sequence collection
+ /// Output video information.
+ public static bool JoinImageSequence(string output, double frameRate = 30, params ImageInfo[] images)
+ {
+ var tempFolderName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString());
+ var temporaryImageFiles = images.Select((imageInfo, index) =>
+ {
+ using var image = Image.FromFile(imageInfo.FullName);
+ FFMpegHelper.ConversionSizeExceptionCheck(image.Width, image.Height);
+ var destinationPath = Path.Combine(tempFolderName, $"{index.ToString().PadLeft(9, '0')}{imageInfo.Extension}");
+ Directory.CreateDirectory(tempFolderName);
+ File.Copy(imageInfo.FullName, destinationPath);
+ return destinationPath;
+ }).ToArray();
+
+ var firstImage = images.First();
+ try
+ {
+ return FFMpegArguments
+ .FromFileInput(Path.Combine(tempFolderName, "%09d.png"), false)
+ .OutputToFile(output, true, options => options
+ .ForcePixelFormat("yuv420p")
+ .Resize(firstImage.Width, firstImage.Height)
+ .WithFramerate(frameRate))
+ .ProcessSynchronously();
+ }
+ finally
+ {
+ Cleanup(temporaryImageFiles);
+ Directory.Delete(tempFolderName);
+ }
+ }
+ ///
+ /// Adds a poster image to an audio file.
+ ///
+ /// Source image file.
+ /// Source audio file.
+ /// Output video file.
+ ///
+ public static bool PosterWithAudio(string image, string audio, string output)
+ {
+ FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4);
+ using (var img = Image.FromFile(image))
+ FFMpegHelper.ConversionSizeExceptionCheck(img.Width, img.Height);
+
+ return FFMpegArguments
+ .FromFileInput(image, false, options => options
+ .Loop(1)
+ .ForceFormat("image2"))
+ .AddFileInput(audio)
+ .OutputToFile(output, true, options => options
+ .ForcePixelFormat("yuv420p")
+ .WithVideoCodec(VideoCodec.LibX264)
+ .WithConstantRateFactor(21)
+ .WithAudioBitrate(AudioQuality.Normal)
+ .UsingShortest())
+ .ProcessSynchronously();
+ }
+
+ ///
+ /// Saves a 'png' thumbnail to an in-memory bitmap
+ ///
+ /// Source video file.
+ /// Seek position where the thumbnail should be taken.
+ /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
+ /// Selected video stream index.
+ /// Input file index
+ /// Bitmap with the requested snapshot.
+ public static Bitmap Snapshot(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
+ {
+ var source = FFProbe.Analyse(input);
+ var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
+ using var ms = new MemoryStream();
+
+ arguments
+ .OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
+ .ForceFormat("rawvideo")))
+ .ProcessSynchronously();
+
+ ms.Position = 0;
+ using var bitmap = new Bitmap(ms);
+ return bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat);
+ }
+ ///
+ /// Saves a 'png' thumbnail to an in-memory bitmap
+ ///
+ /// Source video file.
+ /// Seek position where the thumbnail should be taken.
+ /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
+ /// Selected video stream index.
+ /// Input file index
+ /// Bitmap with the requested snapshot.
+ public static async Task SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
+ {
+ var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
+ var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
+ using var ms = new MemoryStream();
+
+ await arguments
+ .OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
+ .ForceFormat("rawvideo")))
+ .ProcessAsynchronously();
+
+ ms.Position = 0;
+ return new Bitmap(ms);
+ }
+ private static void Cleanup(IEnumerable pathList)
+ {
+ foreach (var path in pathList)
+ {
+ if (File.Exists(path))
+ File.Delete(path);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/FFMpegCore/ImageInfo.cs b/FFMpegCore.Extensions.System.Drawing.Common/ImageInfo.cs
similarity index 100%
rename from FFMpegCore/ImageInfo.cs
rename to FFMpegCore.Extensions.System.Drawing.Common/ImageInfo.cs
diff --git a/FFMpegCore.Test/AudioTest.cs b/FFMpegCore.Test/AudioTest.cs
index 795fedf..d20d21b 100644
--- a/FFMpegCore.Test/AudioTest.cs
+++ b/FFMpegCore.Test/AudioTest.cs
@@ -9,6 +9,8 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using FFMpegCore.Extensions.System.Drawing.Common;
+using FFMpegCore.Test.Utilities;
namespace FFMpegCore.Test
{
@@ -64,11 +66,11 @@ public void Audio_Add()
Assert.IsTrue(File.Exists(outputFile));
}
- [TestMethod]
+ [WindowsOnlyTestMethod]
public void Image_AddAudio()
{
using var outputFile = new TemporaryFile("out.mp4");
- FFMpeg.PosterWithAudio(TestResources.PngImage, TestResources.Mp3Audio, outputFile);
+ FFMpegImage.PosterWithAudio(TestResources.PngImage, TestResources.Mp3Audio, outputFile);
var analysis = FFProbe.Analyse(TestResources.Mp3Audio);
Assert.IsTrue(analysis.Duration.TotalSeconds > 0);
Assert.IsTrue(File.Exists(outputFile));
@@ -239,7 +241,7 @@ public void Audio_Pan_ToMono()
Assert.IsTrue(success);
Assert.AreEqual(1, mediaAnalysis.AudioStreams.Count);
- Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream.ChannelLayout);
+ Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout);
}
[TestMethod, Timeout(10000)]
@@ -257,7 +259,7 @@ public void Audio_Pan_ToMonoNoDefinitions()
Assert.IsTrue(success);
Assert.AreEqual(1, mediaAnalysis.AudioStreams.Count);
- Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream.ChannelLayout);
+ Assert.AreEqual("mono", mediaAnalysis.PrimaryAudioStream!.ChannelLayout);
}
[TestMethod, Timeout(10000)]
diff --git a/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs b/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs
index 6e30999..c849b81 100644
--- a/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs
+++ b/FFMpegCore.Test/FFMpegArgumentProcessorTest.cs
@@ -13,7 +13,7 @@ public void TestInitialize()
{
// After testing reset global configuration to null, to be not wrong for other test relying on configuration
- 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
@@ -69,10 +69,6 @@ public void Processor_Options_CanBeOverridden_And_Configured()
[TestMethod]
public void Options_Global_And_Session_Options_Can_Differ()
{
- FFMpegArgumentProcessor CreateArgumentProcessor() => FFMpegArguments
- .FromFileInput("")
- .OutputToFile("");
-
var globalWorkingDir = "Whatever";
GlobalFFOptions.Configure(new FFOptions { WorkingDirectory = globalWorkingDir });
diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj
index 4ac890c..5a0c11b 100644
--- a/FFMpegCore.Test/FFMpegCore.Test.csproj
+++ b/FFMpegCore.Test/FFMpegCore.Test.csproj
@@ -2,16 +2,31 @@
net6.0
-
false
-
disable
-
default
-
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
PreserveNewest
@@ -28,72 +43,44 @@
PreserveNewest
- Always
-
-
-
-
-
PreserveNewest
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
-
-
-
-
+
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
- Always
+ PreserveNewest
PreserveNewest
-
-
-
-
diff --git a/FFMpegCore.Test/MetaDataBuilderTests.cs b/FFMpegCore.Test/MetaDataBuilderTests.cs
index 747fd9e..5209d4e 100644
--- a/FFMpegCore.Test/MetaDataBuilderTests.cs
+++ b/FFMpegCore.Test/MetaDataBuilderTests.cs
@@ -1,14 +1,7 @@
using FFMpegCore.Builders.MetaData;
-
using Microsoft.VisualStudio.TestTools.UnitTesting;
-
using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
using System.Text.RegularExpressions;
-using System.Threading.Tasks;
namespace FFMpegCore.Test
{
diff --git a/FFMpegCore.Test/Utilities/BitmapSources.cs b/FFMpegCore.Test/Utilities/BitmapSources.cs
index 8ea02e8..044bfa8 100644
--- a/FFMpegCore.Test/Utilities/BitmapSources.cs
+++ b/FFMpegCore.Test/Utilities/BitmapSources.cs
@@ -1,13 +1,15 @@
-using FFMpegCore.Extend;
-using System;
+using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Numerics;
+using System.Runtime.Versioning;
+using FFMpegCore.Extensions.System.Drawing.Common;
using FFMpegCore.Pipes;
-namespace FFMpegCore.Test
+namespace FFMpegCore.Test.Utilities
{
+ [SupportedOSPlatform("windows")]
static class BitmapSource
{
public static IEnumerable CreateBitmaps(int count, PixelFormat fmt, int w, int h)
diff --git a/FFMpegCore.Test/Utilities/WindowsOnlyDataTestMethod.cs b/FFMpegCore.Test/Utilities/WindowsOnlyDataTestMethod.cs
new file mode 100644
index 0000000..8c10054
--- /dev/null
+++ b/FFMpegCore.Test/Utilities/WindowsOnlyDataTestMethod.cs
@@ -0,0 +1,23 @@
+using System.Runtime.InteropServices;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace FFMpegCore.Test.Utilities;
+
+public class WindowsOnlyDataTestMethod : DataTestMethodAttribute
+{
+ public override TestResult[] Execute(ITestMethod testMethod)
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ var message = $"Test not executed on other platforms than Windows";
+ {
+ return new[]
+ {
+ new TestResult { Outcome = UnitTestOutcome.Inconclusive, TestFailureException = new AssertInconclusiveException(message) }
+ };
+ }
+ }
+
+ return base.Execute(testMethod);
+ }
+}
\ No newline at end of file
diff --git a/FFMpegCore.Test/Utilities/WindowsOnlyTestMethod.cs b/FFMpegCore.Test/Utilities/WindowsOnlyTestMethod.cs
new file mode 100644
index 0000000..29300e3
--- /dev/null
+++ b/FFMpegCore.Test/Utilities/WindowsOnlyTestMethod.cs
@@ -0,0 +1,23 @@
+using System.Runtime.InteropServices;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace FFMpegCore.Test.Utilities;
+
+public class WindowsOnlyTestMethod : TestMethodAttribute
+{
+ public override TestResult[] Execute(ITestMethod testMethod)
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ var message = $"Test not executed on other platforms than Windows";
+ {
+ return new[]
+ {
+ new TestResult { Outcome = UnitTestOutcome.Inconclusive, TestFailureException = new AssertInconclusiveException(message) }
+ };
+ }
+ }
+
+ return base.Execute(testMethod);
+ }
+}
\ No newline at end of file
diff --git a/FFMpegCore.Test/VideoTest.cs b/FFMpegCore.Test/VideoTest.cs
index 8f73575..46eac59 100644
--- a/FFMpegCore.Test/VideoTest.cs
+++ b/FFMpegCore.Test/VideoTest.cs
@@ -10,9 +10,12 @@
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
+using System.Runtime.Versioning;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using FFMpegCore.Extensions.System.Drawing.Common;
+using FFMpegCore.Test.Utilities;
namespace FFMpegCore.Test
{
@@ -85,7 +88,8 @@ public void Video_ToH265_MKV_Args()
Assert.IsTrue(success);
}
- [DataTestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyDataTestMethod, Timeout(10000)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format24bppRgb)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format32bppArgb)]
public void Video_ToMP4_Args_Pipe(System.Drawing.Imaging.PixelFormat pixelFormat)
@@ -101,7 +105,8 @@ public void Video_ToMP4_Args_Pipe(System.Drawing.Imaging.PixelFormat pixelFormat
Assert.IsTrue(success);
}
- [TestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public void Video_ToMP4_Args_Pipe_DifferentImageSizes()
{
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@@ -120,8 +125,8 @@ public void Video_ToMP4_Args_Pipe_DifferentImageSizes()
.ProcessSynchronously());
}
-
- [TestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Async()
{
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@@ -140,7 +145,8 @@ public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_Async()
.ProcessAsynchronously());
}
- [TestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats()
{
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@@ -158,9 +164,9 @@ public void Video_ToMP4_Args_Pipe_DifferentPixelFormats()
.WithVideoCodec(VideoCodec.LibX264))
.ProcessSynchronously());
}
-
-
- [TestMethod, Timeout(10000)]
+
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_Async()
{
using var outputFile = new TemporaryFile($"out{VideoType.Mp4.Extension}");
@@ -314,7 +320,8 @@ public void Video_ToTS_Args()
Assert.IsTrue(success);
}
- [DataTestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyDataTestMethod, Timeout(10000)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format24bppRgb)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format32bppArgb)]
public async Task Video_ToTS_Args_Pipe(System.Drawing.Imaging.PixelFormat pixelFormat)
@@ -346,7 +353,8 @@ public async Task Video_ToOGV_Resize()
Assert.IsTrue(success);
}
- [DataTestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyDataTestMethod, Timeout(10000)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format24bppRgb)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format32bppArgb)]
// [DataRow(PixelFormat.Format48bppRgb)]
@@ -381,7 +389,8 @@ public void Scale_Mp4_Multithreaded()
Assert.IsTrue(success);
}
- [DataTestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyDataTestMethod, Timeout(10000)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format24bppRgb)]
[DataRow(System.Drawing.Imaging.PixelFormat.Format32bppArgb)]
// [DataRow(PixelFormat.Format48bppRgb)]
@@ -398,18 +407,20 @@ public void Video_ToMP4_Resize_Args_Pipe(System.Drawing.Imaging.PixelFormat pixe
Assert.IsTrue(success);
}
- [TestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public void Video_Snapshot_InMemory()
{
var input = FFProbe.Analyse(TestResources.Mp4Video);
- using var bitmap = FFMpeg.Snapshot(TestResources.Mp4Video);
-
+ using var bitmap = FFMpegImage.Snapshot(TestResources.Mp4Video);
+
Assert.AreEqual(input.PrimaryVideoStream!.Width, bitmap.Width);
Assert.AreEqual(input.PrimaryVideoStream.Height, bitmap.Height);
Assert.AreEqual(bitmap.RawFormat, ImageFormat.Png);
}
- [TestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public void Video_Snapshot_PersistSnapshot()
{
var outputPath = new TemporaryFile("out.png");
@@ -445,7 +456,7 @@ public void Video_Join()
Assert.AreEqual(input.PrimaryVideoStream.Width, result.PrimaryVideoStream.Width);
}
- [TestMethod, Timeout(10000)]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public void Video_Join_Image_Sequence()
{
var imageSet = new List();
@@ -460,8 +471,8 @@ public void Video_Join_Image_Sequence()
}
});
- using var outputFile = new TemporaryFile("out.mp4");
- var success = FFMpeg.JoinImageSequence(outputFile, images: imageSet.ToArray());
+ var outputFile = new TemporaryFile("out.mp4");
+ var success = FFMpegImage.JoinImageSequence(outputFile, images: imageSet.ToArray());
Assert.IsTrue(success);
var result = FFProbe.Analyse(outputFile);
Assert.AreEqual(3, result.Duration.Seconds);
@@ -554,7 +565,8 @@ public void Video_OutputsData()
Assert.IsTrue(File.Exists(outputFile));
}
- [TestMethod, Timeout(10000)]
+ [SupportedOSPlatform("windows")]
+ [WindowsOnlyTestMethod, Timeout(10000)]
public void Video_TranscodeInMemory()
{
using var resStream = new MemoryStream();
diff --git a/FFMpegCore.sln b/FFMpegCore.sln
index 7a27980..5a9faa8 100644
--- a/FFMpegCore.sln
+++ b/FFMpegCore.sln
@@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore.Test", "FFMpegCo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore.Examples", "FFMpegCore.Examples\FFMpegCore.Examples.csproj", "{3125CF91-FFBD-4E4E-8930-247116AFE772}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFMpegCore.Extensions.System.Drawing.Common", "FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj", "{9C1A4930-9369-4A18-AD98-929A2A510D80}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,10 @@ Global
{3125CF91-FFBD-4E4E-8930-247116AFE772}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3125CF91-FFBD-4E4E-8930-247116AFE772}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3125CF91-FFBD-4E4E-8930-247116AFE772}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9C1A4930-9369-4A18-AD98-929A2A510D80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9C1A4930-9369-4A18-AD98-929A2A510D80}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9C1A4930-9369-4A18-AD98-929A2A510D80}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9C1A4930-9369-4A18-AD98-929A2A510D80}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/FFMpegCore/Extend/StringExtensions.cs b/FFMpegCore/Extend/StringExtensions.cs
index 7b02089..29c8d42 100644
--- a/FFMpegCore/Extend/StringExtensions.cs
+++ b/FFMpegCore/Extend/StringExtensions.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Text;
namespace FFMpegCore.Extend
diff --git a/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs b/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs
index 0f514dc..8b142e4 100644
--- a/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs
+++ b/FFMpegCore/FFMpeg/Arguments/AudibleEncryptionKeyArgument.cs
@@ -4,10 +4,10 @@ public class AudibleEncryptionKeyArgument : IArgument
{
private readonly bool _aaxcMode;
- private readonly string _key;
- private readonly string _iv;
+ private readonly string? _key;
+ private readonly string? _iv;
- private readonly string _activationBytes;
+ private readonly string? _activationBytes;
public AudibleEncryptionKeyArgument(string activationBytes)
diff --git a/FFMpegCore/FFMpeg/Arguments/AudioFiltersArgument.cs b/FFMpegCore/FFMpeg/Arguments/AudioFiltersArgument.cs
index 50b26b3..dac7d15 100644
--- a/FFMpegCore/FFMpeg/Arguments/AudioFiltersArgument.cs
+++ b/FFMpegCore/FFMpeg/Arguments/AudioFiltersArgument.cs
@@ -34,8 +34,8 @@ private string GetText()
public interface IAudioFilterArgument
{
- public string Key { get; }
- public string Value { get; }
+ string Key { get; }
+ string Value { get; }
}
public class AudioFilterOptions
diff --git a/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs b/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs
index 36a504e..20f8cdf 100644
--- a/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs
+++ b/FFMpegCore/FFMpeg/Arguments/IDynamicArgument.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using System.Text;
namespace FFMpegCore.Arguments
{
diff --git a/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs b/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs
index afec731..7038139 100644
--- a/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs
+++ b/FFMpegCore/FFMpeg/Arguments/MapMetadataArgument.cs
@@ -1,9 +1,6 @@
-using FFMpegCore.Extend;
-
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs
index 89bb1fe..5bcb7b1 100644
--- a/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs
+++ b/FFMpegCore/FFMpeg/Arguments/MetaDataArgument.cs
@@ -1,10 +1,7 @@
-using FFMpegCore.Extend;
-
-using System;
+using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/FFMpegCore/FFMpeg/FFMpeg.cs b/FFMpegCore/FFMpeg/FFMpeg.cs
index 9e9e0ce..909a96a 100644
--- a/FFMpegCore/FFMpeg/FFMpeg.cs
+++ b/FFMpegCore/FFMpeg/FFMpeg.cs
@@ -1,7 +1,6 @@
using FFMpegCore.Enums;
using FFMpegCore.Exceptions;
using FFMpegCore.Helpers;
-using FFMpegCore.Pipes;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -12,102 +11,9 @@
namespace FFMpegCore
{
- public static class FFMpeg
+ public static class SnapshotArgumentBuilder
{
- ///
- /// Saves a 'png' thumbnail from the input video to drive
- ///
- /// Source video analysis
- /// Output video file path
- /// Seek position where the thumbnail should be taken.
- /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
- /// Selected video stream index.
- /// Input file index
- /// Bitmap with the requested snapshot.
- public static bool Snapshot(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
- {
- if (Path.GetExtension(output) != FileExtension.Png)
- output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
-
- var source = FFProbe.Analyse(input);
- var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
-
- return arguments
- .OutputToFile(output, true, outputOptions)
- .ProcessSynchronously();
- }
- ///
- /// Saves a 'png' thumbnail from the input video to drive
- ///
- /// Source video analysis
- /// Output video file path
- /// Seek position where the thumbnail should be taken.
- /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
- /// Selected video stream index.
- /// Input file index
- /// Bitmap with the requested snapshot.
- public static async Task SnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
- {
- if (Path.GetExtension(output) != FileExtension.Png)
- output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
-
- var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
- var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
-
- return await arguments
- .OutputToFile(output, true, outputOptions)
- .ProcessAsynchronously();
- }
-
- ///
- /// Saves a 'png' thumbnail to an in-memory bitmap
- ///
- /// Source video file.
- /// Seek position where the thumbnail should be taken.
- /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
- /// Selected video stream index.
- /// Input file index
- /// Bitmap with the requested snapshot.
- public static Bitmap Snapshot(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
- {
- var source = FFProbe.Analyse(input);
- var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
- using var ms = new MemoryStream();
-
- arguments
- .OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
- .ForceFormat("rawvideo")))
- .ProcessSynchronously();
-
- ms.Position = 0;
- using var bitmap = new Bitmap(ms);
- return bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), bitmap.PixelFormat);
- }
- ///
- /// Saves a 'png' thumbnail to an in-memory bitmap
- ///
- /// Source video file.
- /// Seek position where the thumbnail should be taken.
- /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
- /// Selected video stream index.
- /// Input file index
- /// Bitmap with the requested snapshot.
- public static async Task SnapshotAsync(string input, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
- {
- var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
- var (arguments, outputOptions) = BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
- using var ms = new MemoryStream();
-
- await arguments
- .OutputToPipe(new StreamPipeSink(ms), options => outputOptions(options
- .ForceFormat("rawvideo")))
- .ProcessAsynchronously();
-
- ms.Position = 0;
- return new Bitmap(ms);
- }
-
- private static (FFMpegArguments, Action outputOptions) BuildSnapshotArguments(
+ public static (FFMpegArguments, Action outputOptions) BuildSnapshotArguments(
string input,
IMediaAnalysis source,
Size? size = null,
@@ -157,13 +63,61 @@ private static (FFMpegArguments, Action outputOptions) Bu
return null;
}
+ }
+ public static class FFMpeg
+ {
+ ///
+ /// Saves a 'png' thumbnail from the input video to drive
+ ///
+ /// Source video analysis
+ /// Output video file path
+ /// Seek position where the thumbnail should be taken.
+ /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
+ /// Selected video stream index.
+ /// Input file index
+ /// Bitmap with the requested snapshot.
+ public static bool Snapshot(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
+ {
+ if (Path.GetExtension(output) != FileExtension.Png)
+ output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
+
+ var source = FFProbe.Analyse(input);
+ var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
+
+ return arguments
+ .OutputToFile(output, true, outputOptions)
+ .ProcessSynchronously();
+ }
+ ///
+ /// Saves a 'png' thumbnail from the input video to drive
+ ///
+ /// Source video analysis
+ /// Output video file path
+ /// Seek position where the thumbnail should be taken.
+ /// Thumbnail size. If width or height equal 0, the other will be computed automatically.
+ /// Selected video stream index.
+ /// Input file index
+ /// Bitmap with the requested snapshot.
+ public static async Task SnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
+ {
+ if (Path.GetExtension(output) != FileExtension.Png)
+ output = Path.GetFileNameWithoutExtension(output) + FileExtension.Png;
+
+ var source = await FFProbe.AnalyseAsync(input).ConfigureAwait(false);
+ var (arguments, outputOptions) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
+
+ return await arguments
+ .OutputToFile(output, true, outputOptions)
+ .ProcessAsynchronously();
+ }
+
///
/// Convert a video do a different format.
///
- /// Input video source.
+ /// Input video source.
/// Output information.
- /// Target conversion video type.
+ /// Target conversion video format.
/// Conversion target speed/quality (faster speed = lower quality).
/// Video size.
/// Conversion target audio quality.
@@ -237,35 +191,6 @@ public static bool Convert(
};
}
- ///
- /// Adds a poster image to an audio file.
- ///
- /// Source image file.
- /// Source audio file.
- /// Output video file.
- ///
- public static bool PosterWithAudio(string image, string audio, string output)
- {
- FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4);
- using (var imageFile = Image.FromFile(image))
- {
- FFMpegHelper.ConversionSizeExceptionCheck(imageFile);
- }
-
- return FFMpegArguments
- .FromFileInput(image, false, options => options
- .Loop(1)
- .ForceFormat("image2"))
- .AddFileInput(audio)
- .OutputToFile(output, true, options => options
- .ForcePixelFormat("yuv420p")
- .WithVideoCodec(VideoCodec.LibX264)
- .WithConstantRateFactor(21)
- .WithAudioBitrate(AudioQuality.Normal)
- .UsingShortest())
- .ProcessSynchronously();
- }
-
///
/// Joins a list of video files.
///
@@ -299,44 +224,6 @@ public static bool Join(string output, params string[] videos)
}
}
- ///
- /// Converts an image sequence to a video.
- ///
- /// Output video file.
- /// FPS
- /// Image sequence collection
- /// Output video information.
- public static bool JoinImageSequence(string output, double frameRate = 30, params ImageInfo[] images)
- {
- var tempFolderName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString());
- var temporaryImageFiles = images.Select((imageInfo, index) =>
- {
- using var image = Image.FromFile(imageInfo.FullName);
- FFMpegHelper.ConversionSizeExceptionCheck(image);
- var destinationPath = Path.Combine(tempFolderName, $"{index.ToString().PadLeft(9, '0')}{imageInfo.Extension}");
- Directory.CreateDirectory(tempFolderName);
- File.Copy(imageInfo.FullName, destinationPath);
- return destinationPath;
- }).ToArray();
-
- var firstImage = images.First();
- try
- {
- return FFMpegArguments
- .FromFileInput(Path.Combine(tempFolderName, "%09d.png"), false)
- .OutputToFile(output, true, options => options
- .ForcePixelFormat("yuv420p")
- .Resize(firstImage.Width, firstImage.Height)
- .WithFramerate(frameRate))
- .ProcessSynchronously();
- }
- finally
- {
- Cleanup(temporaryImageFiles);
- Directory.Delete(tempFolderName);
- }
- }
-
///
/// Records M3U8 streams to the specified output.
///
@@ -445,15 +332,15 @@ public static IReadOnlyList GetPixelFormats()
return FFMpegCache.PixelFormats.Values.ToList().AsReadOnly();
}
- public static bool TryGetPixelFormat(string name, out PixelFormat fmt)
+ public static bool TryGetPixelFormat(string name, out PixelFormat format)
{
if (!GlobalFFOptions.Current.UseCache)
{
- fmt = GetPixelFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
- return fmt != null;
+ format = GetPixelFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
+ return format != null;
}
else
- return FFMpegCache.PixelFormats.TryGetValue(name, out fmt);
+ return FFMpegCache.PixelFormats.TryGetValue(name, out format);
}
public static PixelFormat GetPixelFormat(string name)
diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs
index c100c85..fad42ce 100644
--- a/FFMpegCore/FFMpeg/FFMpegArguments.cs
+++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs
@@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
diff --git a/FFMpegCore/FFMpegCore.csproj b/FFMpegCore/FFMpegCore.csproj
index 79d191e..ecd0b85 100644
--- a/FFMpegCore/FFMpegCore.csproj
+++ b/FFMpegCore/FFMpegCore.csproj
@@ -1,45 +1,23 @@
-
- en
- https://github.com/rosenbjerg/FFMpegCore
- https://github.com/rosenbjerg/FFMpegCore
-
- A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications
- 4.0.0.0
- README.md
- - Fixes for `MetaDataArgument` (thanks @JKamsker)
-- Support for Audible `aaxc` (thanks @JKamsker)
-- Include errordata in `IMediaAnalysis` (thanks @JKamsker)
-- Pass `FFOptions` properly when using ffprobe (thanks @Notheisz57)
-- CancellationToken support for `AnalyseAsync`
-- Case-insensitive dictionaries for `Tags` and `Disposition`
-- Fix for `PosterWithAudio`
-- Fix for `JoinImageSequence`
-- Updates to dependendies
-- A lot of bug fixes
- 8
- 4.8.0
- MIT
- Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev
- ffmpeg ffprobe convert video audio mediafile resize analyze muxing
- GitHub
- true
- enable
- netstandard2.0
-
+
+ true
+ A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications
+ 5.0.0
+
+
+ ffmpeg ffprobe convert video audio mediafile resize analyze muxing
+ Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev
+ README.md
+
-
-
- Always
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
diff --git a/FFMpegCore/FFProbe/FFProbeAnalysis.cs b/FFMpegCore/FFProbe/FFProbeAnalysis.cs
index cbbb9fd..b81d535 100644
--- a/FFMpegCore/FFProbe/FFProbeAnalysis.cs
+++ b/FFMpegCore/FFProbe/FFProbeAnalysis.cs
@@ -12,7 +12,7 @@ public class FFProbeAnalysis
public Format Format { get; set; } = null!;
[JsonIgnore]
- public IReadOnlyList ErrorData { get; set; }
+ public IReadOnlyList ErrorData { get; set; } = new List();
}
public class FFProbeStream : ITagsContainer, IDispositionContainer
@@ -108,7 +108,7 @@ public class Format : ITagsContainer
public string Size { get; set; } = null!;
[JsonPropertyName("bit_rate")]
- public string BitRate { get; set; } = null!;
+ public string? BitRate { get; set; } = null!;
[JsonPropertyName("probe_score")]
public int ProbeScore { get; set; }
diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs
index e1fbd1d..fd2b135 100644
--- a/FFMpegCore/FFProbe/MediaAnalysis.cs
+++ b/FFMpegCore/FFProbe/MediaAnalysis.cs
@@ -13,7 +13,7 @@ internal MediaAnalysis(FFProbeAnalysis analysis)
VideoStreams = analysis.Streams.Where(stream => stream.CodecType == "video").Select(ParseVideoStream).ToList();
AudioStreams = analysis.Streams.Where(stream => stream.CodecType == "audio").Select(ParseAudioStream).ToList();
SubtitleStreams = analysis.Streams.Where(stream => stream.CodecType == "subtitle").Select(ParseSubtitleStream).ToList();
- ErrorData = analysis.ErrorData ?? new List().AsReadOnly();
+ ErrorData = analysis.ErrorData;
}
private MediaFormat ParseFormat(Format analysisFormat)
diff --git a/FFMpegCore/Helpers/FFMpegHelper.cs b/FFMpegCore/Helpers/FFMpegHelper.cs
index cb3b4cf..97def0f 100644
--- a/FFMpegCore/Helpers/FFMpegHelper.cs
+++ b/FFMpegCore/Helpers/FFMpegHelper.cs
@@ -1,5 +1,4 @@
using System;
-using System.Drawing;
using System.IO;
using FFMpegCore.Exceptions;
using Instances;
@@ -10,13 +9,10 @@ public static class FFMpegHelper
{
private static bool _ffmpegVerified;
- public static void ConversionSizeExceptionCheck(Image image)
- => ConversionSizeExceptionCheck(image.Size.Width, image.Size.Height);
-
public static void ConversionSizeExceptionCheck(IMediaAnalysis info)
=> ConversionSizeExceptionCheck(info.PrimaryVideoStream!.Width, info.PrimaryVideoStream.Height);
- private static void ConversionSizeExceptionCheck(int width, int height)
+ public static void ConversionSizeExceptionCheck(int width, int height)
{
if (height % 2 != 0 || width % 2 != 0 )
throw new ArgumentException("FFMpeg yuv420p encoding requires the width and height to be a multiple of 2!");