mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2025-12-16 19:15:44 +00:00
Compare commits
No commits in common. "adfc781e4c15e461290adc2a8dcd31d04310fa39" and "b10cf5fd761b5231b86a5e8d8a94c272c32bb273" have entirely different histories.
adfc781e4c
...
b10cf5fd76
22 changed files with 65 additions and 469 deletions
|
|
@ -1,9 +0,0 @@
|
||||||
namespace FFMpegCore.Extensions.Downloader.Enums;
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum FFMpegBinaries : ushort
|
|
||||||
{
|
|
||||||
FFMpeg = 1,
|
|
||||||
FFProbe = 2,
|
|
||||||
FFPlay = 4
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.Downloader.Enums;
|
|
||||||
|
|
||||||
public enum FFMpegVersions : ushort
|
|
||||||
{
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/latest")]
|
|
||||||
LatestAvailable,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/6.1")]
|
|
||||||
V6_1,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/5.1")]
|
|
||||||
V5_1,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/4.4.1")]
|
|
||||||
V4_4_1,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/4.2.1")]
|
|
||||||
V4_2_1,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/4.2")]
|
|
||||||
V4_2,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/4.1")]
|
|
||||||
V4_1,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/4.0")]
|
|
||||||
V4_0,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/3.4")]
|
|
||||||
V3_4,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/3.3")]
|
|
||||||
V3_3,
|
|
||||||
|
|
||||||
[Description("https://ffbinaries.com/api/v1/version/3.2")]
|
|
||||||
V3_2
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
namespace FFMpegCore.Extensions.Downloader.Enums;
|
|
||||||
|
|
||||||
public enum SupportedPlatforms : ushort
|
|
||||||
{
|
|
||||||
Windows64,
|
|
||||||
Windows32,
|
|
||||||
Linux64,
|
|
||||||
Linux32,
|
|
||||||
LinuxArmhf,
|
|
||||||
LinuxArmel,
|
|
||||||
LinuxArm64,
|
|
||||||
Osx64
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
namespace FFMpegCore.Extensions.Downloader.Exceptions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Custom exception for FFMpegDownloader
|
|
||||||
/// </summary>
|
|
||||||
public class FFMpegDownloaderException : Exception
|
|
||||||
{
|
|
||||||
public readonly string Detail = "";
|
|
||||||
|
|
||||||
public FFMpegDownloaderException(string message) : base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public FFMpegDownloaderException(string message, string detail) : base(message)
|
|
||||||
{
|
|
||||||
Detail = detail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
using System.ComponentModel;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.Downloader.Extensions;
|
|
||||||
|
|
||||||
public static class EnumExtensions
|
|
||||||
{
|
|
||||||
internal static string GetDescription(this Enum enumValue)
|
|
||||||
{
|
|
||||||
var field = enumValue.GetType().GetField(enumValue.ToString());
|
|
||||||
if (field == null)
|
|
||||||
{
|
|
||||||
return enumValue.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) is DescriptionAttribute attribute)
|
|
||||||
{
|
|
||||||
return attribute.Description;
|
|
||||||
}
|
|
||||||
|
|
||||||
return enumValue.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static TEnum[] GetFlags<TEnum>(this TEnum input) where TEnum : Enum
|
|
||||||
{
|
|
||||||
return Enum.GetValues(input.GetType())
|
|
||||||
.Cast<Enum>()
|
|
||||||
.Where(input.HasFlag)
|
|
||||||
.Cast<TEnum>()
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<IsPackable>true</IsPackable>
|
|
||||||
<Description>FFMpeg downloader extension for FFMpegCore</Description>
|
|
||||||
<PackageVersion>5.0.0</PackageVersion>
|
|
||||||
<PackageOutputPath>../nupkg</PackageOutputPath>
|
|
||||||
<PackageReleaseNotes>
|
|
||||||
- Updated dependencies
|
|
||||||
</PackageReleaseNotes>
|
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze download install</PackageTags>
|
|
||||||
<Authors>Kerry Cao, Malte Rosenbjerg</Authors>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,83 +0,0 @@
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Text.Json;
|
|
||||||
using FFMpegCore.Extensions.Downloader.Enums;
|
|
||||||
using FFMpegCore.Extensions.Downloader.Exceptions;
|
|
||||||
using FFMpegCore.Extensions.Downloader.Extensions;
|
|
||||||
using FFMpegCore.Extensions.Downloader.Models;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.Downloader;
|
|
||||||
|
|
||||||
public static class FFMpegDownloader
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Download the latest FFMpeg suite binaries for current platform
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="version">used to explicitly state the version of binary you want to download</param>
|
|
||||||
/// <param name="binaries">used to explicitly state the binaries you want to download (ffmpeg, ffprobe, ffplay)</param>
|
|
||||||
/// <param name="options">used for specifying binary folder to download binaries into. If not provided, GlobalFFOptions are used</param>
|
|
||||||
/// <param name="platformOverride">used to explicitly state the os and architecture you want to download</param>
|
|
||||||
/// <returns>a list of the binaries that have been successfully downloaded</returns>
|
|
||||||
public static async Task<List<string>> DownloadBinaries(
|
|
||||||
FFMpegVersions version = FFMpegVersions.LatestAvailable,
|
|
||||||
FFMpegBinaries binaries = FFMpegBinaries.FFMpeg | FFMpegBinaries.FFProbe,
|
|
||||||
FFOptions? options = null,
|
|
||||||
SupportedPlatforms? platformOverride = null)
|
|
||||||
{
|
|
||||||
using var httpClient = new HttpClient();
|
|
||||||
|
|
||||||
var versionInfo = await httpClient.GetVersionInfo(version);
|
|
||||||
var binariesDictionary = versionInfo.BinaryInfo?.GetCompatibleDownloadInfo(platformOverride) ??
|
|
||||||
throw new FFMpegDownloaderException("Failed to get compatible download info");
|
|
||||||
|
|
||||||
var successList = new List<string>();
|
|
||||||
var relevantOptions = options ?? GlobalFFOptions.Current;
|
|
||||||
if (string.IsNullOrEmpty(relevantOptions.BinaryFolder))
|
|
||||||
{
|
|
||||||
throw new FFMpegDownloaderException("Binary folder not specified");
|
|
||||||
}
|
|
||||||
|
|
||||||
var binaryFlags = binaries.GetFlags();
|
|
||||||
foreach (var binaryFlag in binaryFlags)
|
|
||||||
{
|
|
||||||
if (binariesDictionary.TryGetValue(binaryFlag.ToString().ToLowerInvariant(), out var binaryUrl))
|
|
||||||
{
|
|
||||||
using var zipStream = await httpClient.GetStreamAsync(new Uri(binaryUrl));
|
|
||||||
var extracted = ExtractZipAndSave(zipStream, relevantOptions.BinaryFolder);
|
|
||||||
successList.AddRange(extracted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return successList;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task<VersionInfo> GetVersionInfo(this HttpClient client, FFMpegVersions version)
|
|
||||||
{
|
|
||||||
var versionUri = version.GetDescription();
|
|
||||||
|
|
||||||
var response = await client.GetAsync(versionUri);
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
throw new FFMpegDownloaderException($"Failed to get version info from {versionUri}", "network error");
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsonString = await response.Content.ReadAsStringAsync();
|
|
||||||
var versionInfo = JsonSerializer.Deserialize<VersionInfo>(jsonString);
|
|
||||||
|
|
||||||
return versionInfo ??
|
|
||||||
throw new FFMpegDownloaderException($"Failed to deserialize version info from {versionUri}", jsonString);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<string> ExtractZipAndSave(Stream zipStream, string binaryFolder)
|
|
||||||
{
|
|
||||||
using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read);
|
|
||||||
foreach (var entry in archive.Entries)
|
|
||||||
{
|
|
||||||
if (entry.Name is "ffmpeg" or "ffmpeg.exe" or "ffprobe.exe" or "ffprobe" or "ffplay.exe" or "ffplay")
|
|
||||||
{
|
|
||||||
var filePath = Path.Combine(binaryFolder, entry.Name);
|
|
||||||
entry.ExtractToFile(filePath, true);
|
|
||||||
yield return filePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
using FFMpegCore.Extensions.Downloader.Enums;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.Downloader.Models;
|
|
||||||
|
|
||||||
internal class BinaryInfo
|
|
||||||
{
|
|
||||||
[JsonPropertyName("windows-64")] public Dictionary<string, string>? Windows64 { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("windows-32")] public Dictionary<string, string>? Windows32 { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("linux-32")] public Dictionary<string, string>? Linux32 { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("linux-64")] public Dictionary<string, string>? Linux64 { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("linux-armhf")] public Dictionary<string, string>? LinuxArmhf { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("linux-armel")] public Dictionary<string, string>? LinuxArmel { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("linux-arm64")] public Dictionary<string, string>? LinuxArm64 { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("osx-64")] public Dictionary<string, string>? Osx64 { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Automatically get the compatible download info for current os and architecture
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="platformOverride"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
||||||
/// <exception cref="PlatformNotSupportedException"></exception>
|
|
||||||
public Dictionary<string, string>? GetCompatibleDownloadInfo(SupportedPlatforms? platformOverride = null)
|
|
||||||
{
|
|
||||||
if (platformOverride is not null)
|
|
||||||
{
|
|
||||||
return platformOverride switch
|
|
||||||
{
|
|
||||||
SupportedPlatforms.Windows64 => Windows64,
|
|
||||||
SupportedPlatforms.Windows32 => Windows32,
|
|
||||||
SupportedPlatforms.Linux64 => Linux64,
|
|
||||||
SupportedPlatforms.Linux32 => Linux32,
|
|
||||||
SupportedPlatforms.LinuxArmhf => LinuxArmhf,
|
|
||||||
SupportedPlatforms.LinuxArmel => LinuxArmel,
|
|
||||||
SupportedPlatforms.LinuxArm64 => LinuxArm64,
|
|
||||||
SupportedPlatforms.Osx64 => Osx64,
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(platformOverride), platformOverride, null)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
{
|
|
||||||
return RuntimeInformation.OSArchitecture == Architecture.X64 ? Windows64 : Windows32;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
||||||
{
|
|
||||||
return RuntimeInformation.OSArchitecture switch
|
|
||||||
{
|
|
||||||
Architecture.X86 => Linux32,
|
|
||||||
Architecture.X64 => Linux64,
|
|
||||||
Architecture.Arm => LinuxArmhf,
|
|
||||||
Architecture.Arm64 => LinuxArm64,
|
|
||||||
_ => LinuxArmel
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && RuntimeInformation.OSArchitecture == Architecture.X64)
|
|
||||||
{
|
|
||||||
return Osx64;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new PlatformNotSupportedException("Unsupported OS or Architecture");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Extensions.Downloader.Models;
|
|
||||||
|
|
||||||
internal record VersionInfo
|
|
||||||
{
|
|
||||||
[JsonPropertyName("version")] public string? Version { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("permalink")] public string? Permalink { get; set; }
|
|
||||||
|
|
||||||
[JsonPropertyName("bin")] public BinaryInfo? BinaryInfo { get; set; }
|
|
||||||
}
|
|
||||||
|
|
@ -5,10 +5,8 @@
|
||||||
<Description>Image extension for FFMpegCore using SkiaSharp</Description>
|
<Description>Image extension for FFMpegCore using SkiaSharp</Description>
|
||||||
<PackageVersion>5.0.3</PackageVersion>
|
<PackageVersion>5.0.3</PackageVersion>
|
||||||
<PackageOutputPath>../nupkg</PackageOutputPath>
|
<PackageOutputPath>../nupkg</PackageOutputPath>
|
||||||
<PackageReleaseNotes>
|
<PackageReleaseNotes>Bump dependencies</PackageReleaseNotes>
|
||||||
- Updated dependencies
|
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing skiasharp</PackageTags>
|
||||||
</PackageReleaseNotes>
|
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio image mediafile resize analyze muxing skia skiasharp</PackageTags>
|
|
||||||
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev, Dimitri Vranken</Authors>
|
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev, Dimitri Vranken</Authors>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,8 @@
|
||||||
<Description>Image extension for FFMpegCore using System.Common.Drawing</Description>
|
<Description>Image extension for FFMpegCore using System.Common.Drawing</Description>
|
||||||
<PackageVersion>5.0.3</PackageVersion>
|
<PackageVersion>5.0.3</PackageVersion>
|
||||||
<PackageOutputPath>../nupkg</PackageOutputPath>
|
<PackageOutputPath>../nupkg</PackageOutputPath>
|
||||||
<PackageReleaseNotes>
|
<PackageReleaseNotes>Bump dependencies</PackageReleaseNotes>
|
||||||
- Updated dependencies
|
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
||||||
</PackageReleaseNotes>
|
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio image mediafile resize analyze muxing</PackageTags>
|
|
||||||
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>
|
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>
|
||||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using FFMpegCore.Arguments;
|
using FFMpegCore.Arguments;
|
||||||
using FFMpegCore.Enums;
|
using FFMpegCore.Enums;
|
||||||
using FFMpegCore.Pipes;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test;
|
namespace FFMpegCore.Test;
|
||||||
|
|
||||||
|
|
@ -9,7 +8,6 @@ namespace FFMpegCore.Test;
|
||||||
public class ArgumentBuilderTest
|
public class ArgumentBuilderTest
|
||||||
{
|
{
|
||||||
private readonly string[] _concatFiles = { "1.mp4", "2.mp4", "3.mp4", "4.mp4" };
|
private readonly string[] _concatFiles = { "1.mp4", "2.mp4", "3.mp4", "4.mp4" };
|
||||||
private readonly int _macOsMaxPipePathLength = 104;
|
|
||||||
private readonly string[] _multiFiles = { "1.mp3", "2.mp3", "3.mp3", "4.mp3" };
|
private readonly string[] _multiFiles = { "1.mp3", "2.mp3", "3.mp3", "4.mp3" };
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
@ -705,18 +703,4 @@ public class ArgumentBuilderTest
|
||||||
var arg = new AudibleEncryptionKeyArgument("62689101");
|
var arg = new AudibleEncryptionKeyArgument("62689101");
|
||||||
Assert.AreEqual("-activation_bytes 62689101", arg.Text);
|
Assert.AreEqual("-activation_bytes 62689101", arg.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void InputPipe_MaxLength_ShorterThanMacOSMax()
|
|
||||||
{
|
|
||||||
var pipePath = new InputPipeArgument(new StreamPipeSource(Stream.Null)).PipePath;
|
|
||||||
Assert.IsLessThan(104, pipePath.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestMethod]
|
|
||||||
public void OutputPipe_MaxLength_ShorterThanMacOSMax()
|
|
||||||
{
|
|
||||||
var pipePath = new OutputPipeArgument(new StreamPipeSink(Stream.Null)).PipePath;
|
|
||||||
Assert.IsLessThan(_macOsMaxPipePathLength, pipePath.Length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
using FFMpegCore.Extensions.Downloader;
|
|
||||||
using FFMpegCore.Extensions.Downloader.Enums;
|
|
||||||
using FFMpegCore.Test.Utilities;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test;
|
|
||||||
|
|
||||||
[TestClass]
|
|
||||||
public class DownloaderTests
|
|
||||||
{
|
|
||||||
private FFOptions _ffOptions;
|
|
||||||
|
|
||||||
[TestInitialize]
|
|
||||||
public void InitializeTestFolder()
|
|
||||||
{
|
|
||||||
var tempDownloadFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
|
||||||
Directory.CreateDirectory(tempDownloadFolder);
|
|
||||||
_ffOptions = new FFOptions { BinaryFolder = tempDownloadFolder };
|
|
||||||
}
|
|
||||||
|
|
||||||
[TestCleanup]
|
|
||||||
public void DeleteTestFolder()
|
|
||||||
{
|
|
||||||
Directory.Delete(_ffOptions.BinaryFolder, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows | OsPlatforms.Linux)]
|
|
||||||
public async Task GetSpecificVersionTest()
|
|
||||||
{
|
|
||||||
var binaries = await FFMpegDownloader.DownloadBinaries(FFMpegVersions.V6_1, options: _ffOptions);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Assert.HasCount(2, binaries);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
binaries.ForEach(File.Delete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows | OsPlatforms.Linux)]
|
|
||||||
public async Task GetAllLatestSuiteTest()
|
|
||||||
{
|
|
||||||
var binaries = await FFMpegDownloader.DownloadBinaries(options: _ffOptions);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Assert.HasCount(2, binaries);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
binaries.ForEach(File.Delete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -20,10 +20,10 @@
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0"/>
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0"/>
|
||||||
<PackageReference Include="MSTest.TestAdapter" Version="4.0.1"/>
|
<PackageReference Include="MSTest.TestAdapter" Version="4.0.1"/>
|
||||||
<PackageReference Include="MSTest.TestFramework" Version="4.0.1"/>
|
<PackageReference Include="MSTest.TestFramework" Version="4.0.1"/>
|
||||||
|
<PackageReference Include="SkiaSharp" Version="3.119.1"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.Downloader\FFMpegCore.Extensions.Downloader.csproj"/>
|
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj"/>
|
<ProjectReference Include="..\FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj"/>
|
<ProjectReference Include="..\FFMpegCore.Extensions.System.Drawing.Common\FFMpegCore.Extensions.System.Drawing.Common.csproj"/>
|
||||||
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
<ProjectReference Include="..\FFMpegCore\FFMpegCore.csproj"/>
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using FFMpegCore.Extensions.Downloader.Extensions;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test.Utilities;
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
internal enum OsPlatforms : ushort
|
|
||||||
{
|
|
||||||
Windows = 1,
|
|
||||||
Linux = 2,
|
|
||||||
MacOS = 4
|
|
||||||
}
|
|
||||||
|
|
||||||
internal class OsSpecificTestMethod : TestMethodAttribute
|
|
||||||
{
|
|
||||||
private readonly IEnumerable<OSPlatform> _supportedOsPlatforms;
|
|
||||||
|
|
||||||
public OsSpecificTestMethod(OsPlatforms supportedOsPlatforms, [CallerFilePath] string callerFilePath = "",
|
|
||||||
[CallerLineNumber] int callerLineNumber = -1) : base(callerFilePath, callerLineNumber)
|
|
||||||
{
|
|
||||||
_supportedOsPlatforms = supportedOsPlatforms.GetFlags()
|
|
||||||
.Select(flag => OSPlatform.Create(flag.ToString().ToUpperInvariant()))
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override async Task<TestResult[]> ExecuteAsync(ITestMethod testMethod)
|
|
||||||
{
|
|
||||||
if (_supportedOsPlatforms.Any(RuntimeInformation.IsOSPlatform))
|
|
||||||
{
|
|
||||||
return await base.ExecuteAsync(testMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
var message = $"Test only executed on specific platforms: {string.Join(", ", _supportedOsPlatforms.Select(platform => platform.ToString()))}";
|
|
||||||
{
|
|
||||||
return
|
|
||||||
[
|
|
||||||
new TestResult { Outcome = UnitTestOutcome.Inconclusive, TestFailureException = new AssertInconclusiveException(message) }
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
28
FFMpegCore.Test/Utilities/WindowsOnlyTestMethod.cs
Normal file
28
FFMpegCore.Test/Utilities/WindowsOnlyTestMethod.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace FFMpegCore.Test.Utilities;
|
||||||
|
|
||||||
|
public class WindowsOnlyTestMethod : TestMethodAttribute
|
||||||
|
{
|
||||||
|
public WindowsOnlyTestMethod([CallerFilePath] string callerFilePath = "", [CallerLineNumber] int callerLineNumber = -1)
|
||||||
|
: base(callerFilePath, callerLineNumber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<TestResult[]> ExecuteAsync(ITestMethod testMethod)
|
||||||
|
{
|
||||||
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
var message = "Test not executed on other platforms than Windows";
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
new TestResult { Outcome = UnitTestOutcome.Inconclusive, TestFailureException = new AssertInconclusiveException(message) }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return await base.ExecuteAsync(testMethod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -110,7 +110,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(PixelFormat.Format24bppRgb)]
|
[DataRow(PixelFormat.Format24bppRgb)]
|
||||||
[DataRow(PixelFormat.Format32bppArgb)]
|
[DataRow(PixelFormat.Format32bppArgb)]
|
||||||
|
|
@ -142,7 +142,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly()
|
public void Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly()
|
||||||
{
|
{
|
||||||
|
|
@ -174,7 +174,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly_Async()
|
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly_Async()
|
||||||
{
|
{
|
||||||
|
|
@ -206,7 +206,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly()
|
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly()
|
||||||
{
|
{
|
||||||
|
|
@ -239,7 +239,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async()
|
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async()
|
||||||
{
|
{
|
||||||
|
|
@ -414,7 +414,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(PixelFormat.Format24bppRgb)]
|
[DataRow(PixelFormat.Format24bppRgb)]
|
||||||
[DataRow(PixelFormat.Format32bppArgb)]
|
[DataRow(PixelFormat.Format32bppArgb)]
|
||||||
|
|
@ -463,7 +463,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(SKColorType.Rgb565)]
|
[DataRow(SKColorType.Rgb565)]
|
||||||
[DataRow(SKColorType.Bgra8888)]
|
[DataRow(SKColorType.Bgra8888)]
|
||||||
|
|
@ -500,7 +500,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
[DataRow(PixelFormat.Format24bppRgb)]
|
[DataRow(PixelFormat.Format24bppRgb)]
|
||||||
[DataRow(PixelFormat.Format32bppArgb)]
|
[DataRow(PixelFormat.Format32bppArgb)]
|
||||||
|
|
@ -533,7 +533,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_Snapshot_InMemory_SystemDrawingCommon()
|
public void Video_Snapshot_InMemory_SystemDrawingCommon()
|
||||||
{
|
{
|
||||||
|
|
@ -857,7 +857,7 @@ public class VideoTest
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
[OsSpecificTestMethod(OsPlatforms.Windows)]
|
[WindowsOnlyTestMethod]
|
||||||
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
|
||||||
public void Video_TranscodeInMemory_WindowsOnly()
|
public void Video_TranscodeInMemory_WindowsOnly()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 17.7.34003.232
|
VisualStudioVersion = 16.0.31005.135
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore", "FFMpegCore\FFMpegCore.csproj", "{19DE2EC2-9955-4712-8096-C22EF6713E4F}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore", "FFMpegCore\FFMpegCore.csproj", "{19DE2EC2-9955-4712-8096-C22EF6713E4F}"
|
||||||
EndProject
|
EndProject
|
||||||
|
|
@ -13,8 +13,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore.Extensions.Syste
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore.Extensions.SkiaSharp", "FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj", "{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore.Extensions.SkiaSharp", "FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj", "{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFMpegCore.Extensions.Downloader", "FFMpegCore.Extensions.Downloader\FFMpegCore.Extensions.Downloader.csproj", "{5FA30158-CAB0-44FD-AD98-C31F5E3D5A56}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -41,10 +39,6 @@ Global
|
||||||
{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}.Release|Any CPU.Build.0 = Release|Any CPU
|
{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{5FA30158-CAB0-44FD-AD98-C31F5E3D5A56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{5FA30158-CAB0-44FD-AD98-C31F5E3D5A56}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{5FA30158-CAB0-44FD-AD98-C31F5E3D5A56}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{5FA30158-CAB0-44FD-AD98-C31F5E3D5A56}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,10 @@ namespace FFMpegCore.Arguments;
|
||||||
public abstract class PipeArgument
|
public abstract class PipeArgument
|
||||||
{
|
{
|
||||||
private readonly PipeDirection _direction;
|
private readonly PipeDirection _direction;
|
||||||
private readonly object _pipeLock = new();
|
|
||||||
|
|
||||||
protected PipeArgument(PipeDirection direction)
|
protected PipeArgument(PipeDirection direction)
|
||||||
{
|
{
|
||||||
PipeName = PipeHelpers.GetUniquePipeName();
|
PipeName = PipeHelpers.GetUnqiuePipeName();
|
||||||
_direction = direction;
|
_direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,8 +21,6 @@ public abstract class PipeArgument
|
||||||
public abstract string Text { get; }
|
public abstract string Text { get; }
|
||||||
|
|
||||||
public void Pre()
|
public void Pre()
|
||||||
{
|
|
||||||
lock (_pipeLock)
|
|
||||||
{
|
{
|
||||||
if (Pipe != null)
|
if (Pipe != null)
|
||||||
{
|
{
|
||||||
|
|
@ -32,17 +29,13 @@ public abstract class PipeArgument
|
||||||
|
|
||||||
Pipe = new NamedPipeServerStream(PipeName, _direction, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
|
Pipe = new NamedPipeServerStream(PipeName, _direction, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void Post()
|
public void Post()
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"Disposing NamedPipeServerStream on {GetType().Name}");
|
Debug.WriteLine($"Disposing NamedPipeServerStream on {GetType().Name}");
|
||||||
lock (_pipeLock)
|
|
||||||
{
|
|
||||||
Pipe?.Dispose();
|
Pipe?.Dispose();
|
||||||
Pipe = null!;
|
Pipe = null!;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async Task During(CancellationToken cancellationToken = default)
|
public async Task During(CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
|
@ -57,15 +50,12 @@ public abstract class PipeArgument
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"Disconnecting NamedPipeServerStream on {GetType().Name}");
|
Debug.WriteLine($"Disconnecting NamedPipeServerStream on {GetType().Name}");
|
||||||
lock (_pipeLock)
|
|
||||||
{
|
|
||||||
if (Pipe is { IsConnected: true })
|
if (Pipe is { IsConnected: true })
|
||||||
{
|
{
|
||||||
Pipe.Disconnect();
|
Pipe.Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract Task ProcessDataAsync(CancellationToken token);
|
protected abstract Task ProcessDataAsync(CancellationToken token);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@ namespace FFMpegCore.Pipes;
|
||||||
|
|
||||||
internal static class PipeHelpers
|
internal static class PipeHelpers
|
||||||
{
|
{
|
||||||
public static string GetUniquePipeName()
|
public static string GetUnqiuePipeName()
|
||||||
{
|
{
|
||||||
return $"FFMpegCore_{Guid.NewGuid().ToString("N").Substring(0, 16)}";
|
return $"FFMpegCore_{Guid.NewGuid().ToString("N").Substring(0, 5)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetPipePath(string pipeName)
|
public static string GetPipePath(string pipeName)
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,15 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<IsPackable>true</IsPackable>
|
<IsPackable>true</IsPackable>
|
||||||
<Description>A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications</Description>
|
<Description>A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications</Description>
|
||||||
<PackageVersion>5.3.0</PackageVersion>
|
<PackageVersion>5.2.0</PackageVersion>
|
||||||
<PackageOutputPath>../nupkg</PackageOutputPath>
|
<PackageOutputPath>../nupkg</PackageOutputPath>
|
||||||
<PackageReleaseNotes>
|
<PackageReleaseNotes>- **Instances and Packages Updates**: Updates to various instances and packages by rosenbjerg.
|
||||||
- **Fixed race condition on Named pipe dispose/disconnect** by techtel-pstevens
|
- **Audio and Video Enhancements**: Additions include a Copy option to Audio Codec and a Crop option to Arguments by brett-baker; video-stream level added to FFProbe analysis by Kaaybi; AV1 support for smaller snapshots and videos by BenediktBertsch; multiple input files support by AddyMills; HDR color properties support added to FFProbe analysis by Tomiscout.
|
||||||
- **More extensions for snapshot function(jpg, bmp, webp)** by GorobVictor
|
- **System.Text.Json Bump**: Update by Kaaybi.
|
||||||
- **Include more GUID characters in pipe path** by reima, rosenbjerg
|
- **FFMpeg Processors and Utilities**: Modification for handling durations over 24 hours in `FFMpegArgumentProcessor` by alahane-techtel; fix for snapshots with correct width/height from rotated videos by Hagfjall.
|
||||||
- **Updated dependencies and minor cleanup**: by rosenbjerg
|
- **Feature Additions and Fixes**: Support for multiple outputs and tee muxer by duggaraju; custom ffprob arguments by vfrz; fix for null reference exception with tags container by rosenbjerg; Chapter Modell change by vortex852456; codec copy added to the SaveM3U8Stream method by rpaschoal.
|
||||||
|
- **Closed and Non-merged Contributions**: Notable closed contributions include JSON source generators usage by onionware-github; Snapshot overload by 3UR; FromRawInput method by pedoc; runtime ffmpeg suite installation by yuqian5; and support for scale_npp by vicwilliam.
|
||||||
|
- **Miscellaneous Fixes**: Minor readme corrections by NaBian; fix for ffmpeg path issue by devedse.
|
||||||
</PackageReleaseNotes>
|
</PackageReleaseNotes>
|
||||||
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
|
||||||
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>
|
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>
|
||||||
|
|
|
||||||
|
|
@ -184,12 +184,7 @@ If you want to use `System.Drawing.Bitmap`s as `IVideoFrame`s, a `BitmapVideoFra
|
||||||
|
|
||||||
# Binaries
|
# Binaries
|
||||||
|
|
||||||
## Runtime Auto Installation
|
## Installation
|
||||||
You can install a version of ffmpeg suite at runtime using `FFMpegDownloader.DownloadFFMpegSuite();`
|
|
||||||
|
|
||||||
This feature uses the api from [ffbinaries](https://ffbinaries.com/api).
|
|
||||||
|
|
||||||
## Manual Installation
|
|
||||||
|
|
||||||
If you prefer to manually download them, visit [ffbinaries](https://ffbinaries.com/downloads)
|
If you prefer to manually download them, visit [ffbinaries](https://ffbinaries.com/downloads)
|
||||||
or [zeranoe Windows builds](https://ffmpeg.zeranoe.com/builds/).
|
or [zeranoe Windows builds](https://ffmpeg.zeranoe.com/builds/).
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue