Compare commits

...

88 commits

Author SHA1 Message Date
Malte Rosenbjerg
adfc781e4c
Merge branch 'main' into Add_Segment_muxer_output 2025-10-17 20:38:10 +02:00
Malte Rosenbjerg
fc5e8a66e3 Prep for release 2025-10-17 20:36:58 +02:00
Malte Rosenbjerg
46fb46381d
Merge pull request #581 from rosenbjerg/include-more-guid-chars-in-pipe-path
Include more guid chars in pipe path
2025-10-17 20:34:45 +02:00
Malte Rosenbjerg
77d13e8143
Update FFMpegCore.Test/ArgumentBuilderTest.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-17 19:54:15 +02:00
Malte Rosenbjerg
1b0051b234 Create variable for holding macOS max pipe path length to avoid magic number 2025-10-17 19:53:38 +02:00
Malte Rosenbjerg
f0b5859afd Add test verifying that full pipe path is less than maximum pipe path length on macos 2025-10-17 19:47:41 +02:00
Malte Rosenbjerg
c0b5e8e52f Fix typo 2025-10-17 19:47:08 +02:00
Malte Rosenbjerg
94174a28db Include 16 guid chars in pipe name 2025-10-17 19:47:01 +02:00
Malte Rosenbjerg
cf775ae7a9
Merge pull request #571 from techtel-pstevens/main
Fixed race condition on Named pipe dispose/disconnect
2025-10-17 15:43:57 +02:00
Malte Rosenbjerg
767a3f59ab
Merge branch 'main' into main 2025-10-17 15:37:38 +02:00
Malte Rosenbjerg
1722b5496d
Merge pull request #442 from yuqian5/main
Ability to install ffmpeg suite at runtime added with FFMpegDownloader
2025-10-17 15:34:00 +02:00
Malte Rosenbjerg
bbdbe5592a Merge branch 'main' of https://github.com/yuqian5/FFMpegCore into pr/442 2025-10-17 15:22:42 +02:00
Malte Rosenbjerg
8b8701ef44 Make Detail prop on FFMpegDownloaderException a readonly field 2025-10-17 15:22:35 +02:00
Malte Rosenbjerg
abf2ab5ee7 Ensure sub tempfolder is deleted after use 2025-10-17 15:22:17 +02:00
Malte Rosenbjerg
81bf155c38
Update README.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-17 15:20:51 +02:00
Malte Rosenbjerg
0a0e6c4985
Update FFMpegCore.Test/Utilities/OsSpecificTestMethod.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-17 15:20:44 +02:00
Malte Rosenbjerg
7794276536
Update FFMpegCore.Extensions.Downloader/Enums/FFMpegBinaries.cs
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-17 15:19:12 +02:00
Malte Rosenbjerg
8720e19b91 Fix usage of temp subfolder 2025-10-17 15:17:27 +02:00
Malte Rosenbjerg
54e28cea23 Use subfolder in temp folder for testing download of binaries 2025-10-17 15:15:02 +02:00
Malte Rosenbjerg
2a25bff836 Remove WindowsOnlyTestMethod and use OsSpecificTestMethod 2025-10-17 15:14:42 +02:00
Malte Rosenbjerg
a71a55741f Use OsSpecificTestMethod on GetAllLatestSuiteTest 2025-10-17 15:08:35 +02:00
Malte Rosenbjerg
bfcb1b9544 Minor refactor to use yield return 2025-10-17 15:08:13 +02:00
Malte Rosenbjerg
1a49b4eec3 Rename Latest enum member 2025-10-17 15:08:00 +02:00
Malte Rosenbjerg
3404d63655 Rename download function 2025-10-17 15:07:45 +02:00
Malte Rosenbjerg
8f2d3d7125 Remove specification of .NET Standard 2.1 2025-10-17 15:07:10 +02:00
Malte Rosenbjerg
ad27076c1f Refactor for conciseness 2025-10-17 15:01:11 +02:00
Malte Rosenbjerg
d7fec62d2e Only run downloader tests on windows and linux since macos CI runs on arm which builds are not available for 2025-10-17 15:01:00 +02:00
Malte Rosenbjerg
3be446880a Only run downloader tests on windows and linux since macos CI runs on arm which builds are not available for 2025-10-17 14:45:11 +02:00
Malte Rosenbjerg
07253b4b49 Update nuget package authors 2025-10-17 10:35:05 +02:00
Malte Rosenbjerg
af47c9ae94 Throw exception if binary folder not specified 2025-10-17 10:34:49 +02:00
Malte Rosenbjerg
b1eb8da6a9 Delete downloaded binaries after assert 2025-10-17 10:34:27 +02:00
Malte Rosenbjerg
2852692250 Fix typo 2025-10-17 10:33:29 +02:00
Malte Rosenbjerg
f919a05d43 Make download tests run async 2025-10-17 10:24:26 +02:00
Malte Rosenbjerg
bb90cb1ea1 Merge branch 'main' into pr/442 2025-10-17 10:21:42 +02:00
Malte Rosenbjerg
ea8c493f8a Merge branch 'main' into pr/571 2025-10-16 14:46:05 +02:00
Malte Rosenbjerg
7c71a70a0c Revert "Improve test readability"
This reverts commit 85e7170fd9.
2025-10-16 14:26:53 +02:00
Malte Rosenbjerg
85e7170fd9 Improve test readability 2025-10-16 14:04:10 +02:00
Malte Rosenbjerg
2d149d4c9a Initialize lock inline 2025-10-16 13:52:17 +02:00
Malte Rosenbjerg
0387e47396 Merge branch 'main' into pr/571 2025-10-16 13:50:27 +02:00
Malte Rosenbjerg
262c3f1b4f Wrap remaining Pipe access in lock 2025-10-16 13:10:33 +02:00
Malte Rosenbjerg
29f40b88af Use private readonly object for locking 2025-10-16 13:09:52 +02:00
Malte Rosenbjerg
6fc811bc39 Move comment 2025-10-16 13:04:58 +02:00
Malte Rosenbjerg
5f2147e207 Fix formatting 2025-10-16 13:03:26 +02:00
Malte Rosenbjerg
066ca894ba Merge branch 'main' into pr/571 2025-10-16 12:58:20 +02:00
Malte Rosenbjerg
9a5b9ca19d
Merge branch 'main' into main 2025-10-16 10:10:19 +02:00
Malte Rosenbjerg
cae2e04a54
Merge branch 'main' into main 2025-10-16 10:00:07 +02:00
Malte Rosenbjerg
50fcddab9b
Merge branch 'main' into main 2025-09-09 08:22:17 +02:00
Ashish
67808c2e4a
Merge pull request #1 from alahane-techtel/alahane-techtel-patch-1/NamedPipeCleanupRaceCondition
Fixed race condition on Named pipe dispose/disconnect
2025-07-07 17:04:39 +10:00
Ashish
d608026d17
Fixed race condition on Named pipe dispose/disconnect 2025-07-04 23:12:05 +10:00
Kerry Cao
483c526772 linter fix 2025-01-28 21:44:34 -05:00
Kerry Cao
1c03587cd8 obsolete webclient replaced with httpclient 2025-01-28 21:42:12 -05:00
Kerry Cao
644c41df90 GetSpecificVersionTest assertion fix 2025-01-28 21:41:44 -05:00
Kerry Cao
9f6249cb5f re-enable DownloaderTests.cs 2025-01-27 22:43:20 -05:00
Kerry Cao
88c7f7bf7c debug 2025-01-27 22:39:35 -05:00
Kerry Cao
33098ad4de linter fix 2025-01-27 22:37:03 -05:00
Kerry Cao
91a2ceaceb Test update to try and resolve failed tests 2025-01-27 22:34:57 -05:00
Kerry Cao
8e32d68877 format cleanup to avoid lint error 2025-01-27 22:30:22 -05:00
Kerry Cao
7be5496305 major refactoring 2025-01-27 22:22:47 -05:00
K
995690c0f3
Merge branch 'rosenbjerg:main' into main 2025-01-27 21:42:14 -05:00
Malte Rosenbjerg
c44170ba8e
Merge branch 'main' into main 2024-12-04 23:08:27 +01:00
Malte Rosenbjerg
a91e309da5
Merge branch 'main' into main 2024-12-04 20:53:07 +01:00
Malte Rosenbjerg
ac3794e753
Merge branch 'main' into main 2024-12-04 20:49:20 +01:00
K
09ae9447c8
version 5.1 and 6.1 added 2024-01-04 16:59:25 -07:00
K
105a26bf5e
Merge branch 'rosenbjerg:main' into main 2024-01-04 15:43:12 -07:00
K
6524b1cd4d
Update DownloaderTests.cs 2023-10-10 15:59:11 -06:00
K
22fa002394
Debug for CI failure 2023-10-10 15:50:59 -06:00
K
5bedbdb107
Update README.md 2023-10-10 15:45:14 -06:00
Malte Rosenbjerg
bba4a9f39b
Merge branch 'main' into main 2023-10-05 12:17:18 +02:00
Malte Rosenbjerg
882cdf849e
Merge branch 'main' into main 2023-10-05 09:21:55 +02:00
Kerry Cao
ae5ae973fa FFMpegCore.Downloader renamed to FFMpegCore.Extensions.Downloader 2023-09-06 14:07:08 -06:00
Kerry Cao
2b66b82d8d Merge remote-tracking branch 'origin/main' 2023-09-06 13:45:32 -06:00
Kerry Cao
d978d7d9b4 ffmpeg downloader moved to separate package 2023-09-06 13:45:22 -06:00
Kerry Cao
dfc486db1d ffmpeg downloader moved to seperate package 2023-09-06 13:42:22 -06:00
Kerry Cao
937db76e00 format fix for lint 2023-09-06 13:22:13 -06:00
Kerry Cao
df8d97ebbb allow os and architecture overrider 2023-09-06 13:19:47 -06:00
Kerry Cao
ae92e9370c Merge remote-tracking branch 'origin/main'
# Conflicts:
#	FFMpegCore.Test/DownloaderTests.cs
#	FFMpegCore/Helpers/FFMpegDownloader.cs
2023-09-06 01:26:56 -06:00
Kerry Cao
da7d1fafed support added for linux, macos
win32, win64, lnx32, lnx64, lnx-armhf, lnx-armel, lnx-arm64, osx64
2023-09-06 01:25:51 -06:00
KCYQ
97fcd3b95e
Merge branch 'main' into main 2023-06-04 16:48:47 +08:00
KCYQ
cf7fd2fdf2
Merge branch 'main' into main 2023-05-06 20:58:04 -06:00
Kerry Cao
463fb9bf6b Reformatted to fix lint error 2023-05-05 01:54:50 -06:00
Kerry Cao
a647f44029 refactoring and reformatting 2023-05-05 01:47:08 -06:00
Kerry Cao
debb868b38 README.md updated to include ffmpegdownloader usage 2023-05-05 01:34:21 -06:00
Kerry Cao
d68ce8e953 Methods renamed to remove auto prefix 2023-05-05 01:30:52 -06:00
Kerry Cao
657ee5ff5d Comments added 2023-05-05 01:21:53 -06:00
Kerry Cao
d44c77c958 Merge remote-tracking branch 'origin/main' 2023-04-11 22:43:04 -06:00
Kerry Cao
a4bb69a8a8 changes made to support multiple version downloads for windows 2023-04-11 22:42:51 -06:00
KCYQ
7c333a723a
Merge pull request #1 from rosenbjerg/main
Merge with upstream
2023-04-11 21:57:40 -06:00
Kerry Cao
9db4ba75b4 features to auto download ffmpeg binaries added 2023-04-11 21:55:30 -06:00
22 changed files with 469 additions and 65 deletions

View file

@ -0,0 +1,9 @@
namespace FFMpegCore.Extensions.Downloader.Enums;
[Flags]
public enum FFMpegBinaries : ushort
{
FFMpeg = 1,
FFProbe = 2,
FFPlay = 4
}

View file

@ -0,0 +1,39 @@
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
}

View file

@ -0,0 +1,13 @@
namespace FFMpegCore.Extensions.Downloader.Enums;
public enum SupportedPlatforms : ushort
{
Windows64,
Windows32,
Linux64,
Linux32,
LinuxArmhf,
LinuxArmel,
LinuxArm64,
Osx64
}

View file

@ -0,0 +1,18 @@
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;
}
}

View file

@ -0,0 +1,31 @@
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();
}
}

View file

@ -0,0 +1,19 @@
<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>

View file

@ -0,0 +1,83 @@
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;
}
}
}
}

View file

@ -0,0 +1,74 @@
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");
}
}

View file

@ -0,0 +1,12 @@
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; }
}

View file

@ -5,8 +5,10 @@
<Description>Image extension for FFMpegCore using SkiaSharp</Description>
<PackageVersion>5.0.3</PackageVersion>
<PackageOutputPath>../nupkg</PackageOutputPath>
<PackageReleaseNotes>Bump dependencies</PackageReleaseNotes>
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing skiasharp</PackageTags>
<PackageReleaseNotes>
- Updated dependencies
</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>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
</PropertyGroup>

View file

@ -5,8 +5,10 @@
<Description>Image extension for FFMpegCore using System.Common.Drawing</Description>
<PackageVersion>5.0.3</PackageVersion>
<PackageOutputPath>../nupkg</PackageOutputPath>
<PackageReleaseNotes>Bump dependencies</PackageReleaseNotes>
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
<PackageReleaseNotes>
- Updated dependencies
</PackageReleaseNotes>
<PackageTags>ffmpeg ffprobe convert video audio image mediafile resize analyze muxing</PackageTags>
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
</PropertyGroup>

View file

@ -1,6 +1,7 @@
using System.Drawing;
using FFMpegCore.Arguments;
using FFMpegCore.Enums;
using FFMpegCore.Pipes;
namespace FFMpegCore.Test;
@ -8,6 +9,7 @@ namespace FFMpegCore.Test;
public class ArgumentBuilderTest
{
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" };
[TestMethod]
@ -703,4 +705,18 @@ public class ArgumentBuilderTest
var arg = new AudibleEncryptionKeyArgument("62689101");
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);
}
}

View file

@ -0,0 +1,53 @@
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);
}
}
}

View file

@ -20,10 +20,10 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.0"/>
<PackageReference Include="MSTest.TestAdapter" Version="4.0.1"/>
<PackageReference Include="MSTest.TestFramework" Version="4.0.1"/>
<PackageReference Include="SkiaSharp" Version="3.119.1"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FFMpegCore.Extensions.Downloader\FFMpegCore.Extensions.Downloader.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\FFMpegCore.csproj"/>

View file

@ -0,0 +1,42 @@
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) }
];
}
}
}

View file

@ -1,28 +0,0 @@
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);
}
}

View file

@ -110,7 +110,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
[DataRow(PixelFormat.Format24bppRgb)]
[DataRow(PixelFormat.Format32bppArgb)]
@ -142,7 +142,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly()
{
@ -174,7 +174,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public async Task Video_ToMP4_Args_Pipe_DifferentImageSizes_WindowsOnly_Async()
{
@ -206,7 +206,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly()
{
@ -239,7 +239,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public async Task Video_ToMP4_Args_Pipe_DifferentPixelFormats_WindowsOnly_Async()
{
@ -414,7 +414,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
[DataRow(PixelFormat.Format24bppRgb)]
[DataRow(PixelFormat.Format32bppArgb)]
@ -463,7 +463,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
[DataRow(SKColorType.Rgb565)]
[DataRow(SKColorType.Bgra8888)]
@ -500,7 +500,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
[DataRow(PixelFormat.Format24bppRgb)]
[DataRow(PixelFormat.Format32bppArgb)]
@ -533,7 +533,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_Snapshot_InMemory_SystemDrawingCommon()
{
@ -857,7 +857,7 @@ public class VideoTest
}
[SupportedOSPlatform("windows")]
[WindowsOnlyTestMethod]
[OsSpecificTestMethod(OsPlatforms.Windows)]
[Timeout(BaseTimeoutMilliseconds, CooperativeCancellation = true)]
public void Video_TranscodeInMemory_WindowsOnly()
{

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31005.135
# Visual Studio Version 17
VisualStudioVersion = 17.7.34003.232
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore", "FFMpegCore\FFMpegCore.csproj", "{19DE2EC2-9955-4712-8096-C22EF6713E4F}"
EndProject
@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore.Extensions.Syste
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FFMpegCore.Extensions.SkiaSharp", "FFMpegCore.Extensions.SkiaSharp\FFMpegCore.Extensions.SkiaSharp.csproj", "{5A76F9B7-3681-4551-A9B6-8D3AC5DA1090}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FFMpegCore.Extensions.Downloader", "FFMpegCore.Extensions.Downloader\FFMpegCore.Extensions.Downloader.csproj", "{5FA30158-CAB0-44FD-AD98-C31F5E3D5A56}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -39,6 +41,10 @@ Global
{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.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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -7,10 +7,11 @@ namespace FFMpegCore.Arguments;
public abstract class PipeArgument
{
private readonly PipeDirection _direction;
private readonly object _pipeLock = new();
protected PipeArgument(PipeDirection direction)
{
PipeName = PipeHelpers.GetUnqiuePipeName();
PipeName = PipeHelpers.GetUniquePipeName();
_direction = direction;
}
@ -22,19 +23,25 @@ public abstract class PipeArgument
public void Pre()
{
if (Pipe != null)
lock (_pipeLock)
{
throw new InvalidOperationException("Pipe already has been opened");
}
if (Pipe != null)
{
throw new InvalidOperationException("Pipe already has been opened");
}
Pipe = new NamedPipeServerStream(PipeName, _direction, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
Pipe = new NamedPipeServerStream(PipeName, _direction, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
}
}
public void Post()
{
Debug.WriteLine($"Disposing NamedPipeServerStream on {GetType().Name}");
Pipe?.Dispose();
Pipe = null!;
lock (_pipeLock)
{
Pipe?.Dispose();
Pipe = null!;
}
}
public async Task During(CancellationToken cancellationToken = default)
@ -50,9 +57,12 @@ public abstract class PipeArgument
finally
{
Debug.WriteLine($"Disconnecting NamedPipeServerStream on {GetType().Name}");
if (Pipe is { IsConnected: true })
lock (_pipeLock)
{
Pipe.Disconnect();
if (Pipe is { IsConnected: true })
{
Pipe.Disconnect();
}
}
}
}

View file

@ -4,9 +4,9 @@ namespace FFMpegCore.Pipes;
internal static class PipeHelpers
{
public static string GetUnqiuePipeName()
public static string GetUniquePipeName()
{
return $"FFMpegCore_{Guid.NewGuid().ToString("N").Substring(0, 5)}";
return $"FFMpegCore_{Guid.NewGuid().ToString("N").Substring(0, 16)}";
}
public static string GetPipePath(string pipeName)

View file

@ -3,15 +3,13 @@
<PropertyGroup>
<IsPackable>true</IsPackable>
<Description>A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications</Description>
<PackageVersion>5.2.0</PackageVersion>
<PackageVersion>5.3.0</PackageVersion>
<PackageOutputPath>../nupkg</PackageOutputPath>
<PackageReleaseNotes>- **Instances and Packages Updates**: Updates to various instances and packages by rosenbjerg.
- **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.
- **System.Text.Json Bump**: Update by Kaaybi.
- **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.
- **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>
- **Fixed race condition on Named pipe dispose/disconnect** by techtel-pstevens
- **More extensions for snapshot function(jpg, bmp, webp)** by GorobVictor
- **Include more GUID characters in pipe path** by reima, rosenbjerg
- **Updated dependencies and minor cleanup**: by rosenbjerg
</PackageReleaseNotes>
<PackageTags>ffmpeg ffprobe convert video audio mediafile resize analyze muxing</PackageTags>
<Authors>Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev</Authors>

View file

@ -184,7 +184,12 @@ If you want to use `System.Drawing.Bitmap`s as `IVideoFrame`s, a `BitmapVideoFra
# Binaries
## Installation
## Runtime Auto 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)
or [zeranoe Windows builds](https://ffmpeg.zeranoe.com/builds/).