From 9db4ba75b45a2a55da2feabf973a459865d1acb7 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Tue, 11 Apr 2023 21:55:30 -0600 Subject: [PATCH 01/17] features to auto download ffmpeg binaries added --- FFMpegCore.Test/DownloaderTests.cs | 27 +++++++++++ FFMpegCore/Helpers/FFMpegDownloader.cs | 64 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 FFMpegCore.Test/DownloaderTests.cs create mode 100644 FFMpegCore/Helpers/FFMpegDownloader.cs diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs new file mode 100644 index 00000000..301078ae --- /dev/null +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -0,0 +1,27 @@ +using System.Runtime.InteropServices; +using FFMpegCore.Helpers; + +namespace FFMpegCore.Test; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +public class DownloaderTests +{ + [TestClass] + public class FFMpegDownloaderTest + { + [TestMethod] + public void GetLatestVersionTest() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var files = FFMpegDownloader.GetLatestVersion(); + Assert.IsTrue(files.Count == 3); + } + else + { + Assert.Inconclusive("This test is only for Windows"); + } + + } + } +} diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs new file mode 100644 index 00000000..7767683e --- /dev/null +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -0,0 +1,64 @@ +using System.ComponentModel; +using System.Net; +using System.IO; +using System.IO.Compression; + + +namespace FFMpegCore.Helpers; +using System.Runtime.InteropServices; + +/// +/// Downloads the latest FFMpeg binaries from GitHub. Only supported for windows at the moment. +/// +public class FFMpegDownloader // this class is built to be easily modified to support other platforms +{ + /// + /// List of URLs to download FFMpeg from. + /// + private static Dictionary FFMpegDownloadUrls = new() + { + { "windows", "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip" } + }; + + public static List GetLatestVersion() + { + var os = GetOSPlatform(); + var zipStream = DownloadFFMpeg(new Uri(FFMpegDownloadUrls[os])); + return ExtractAndSave(zipStream); + } + + private static MemoryStream DownloadFFMpeg(Uri address) + { + var client = new WebClient(); + var zipStream = new MemoryStream(client.DownloadData(address)); + zipStream.Position = 0; + + return zipStream; + } + + private static List ExtractAndSave(Stream zipStream) + { + using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read); + List files = new(); + foreach (var entry in archive.Entries) + { + if (entry.Name is "ffmpeg.exe" or "ffmpeg" or "ffprobe.exe") + { + entry.ExtractToFile(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name), true); + files.Add(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name)); + } + } + + return files; + } + + private static string GetOSPlatform() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return "windows"; + } + + throw new PlatformNotSupportedException("Auto download is only supported on Windows."); + } +} From a4bb69a8a8b94cab0ba8a61e16263fddaf1789c5 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Tue, 11 Apr 2023 22:42:51 -0600 Subject: [PATCH 02/17] changes made to support multiple version downloads for windows --- FFMpegCore.Test/DownloaderTests.cs | 70 +++++++++++++----- FFMpegCore/Helpers/FFMpegDownloader.cs | 99 +++++++++++++++++++++----- 2 files changed, 137 insertions(+), 32 deletions(-) diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index 301078ae..2d968ad2 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -1,27 +1,65 @@ using System.Runtime.InteropServices; using FFMpegCore.Helpers; +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace FFMpegCore.Test; -using Microsoft.VisualStudio.TestTools.UnitTesting; +[TestClass] public class DownloaderTests { - [TestClass] - public class FFMpegDownloaderTest + [TestMethod] + public void GetLatestSuiteTest() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var fileNames = FFMpegDownloader.AutoDownloadFFMpegSuite(); + Assert.IsTrue(fileNames.Count == 3); + } + else + { + Assert.Inconclusive("This test is only for Windows"); + } + } + + [TestMethod] + public void GetLatestFFMpegTest() { - [TestMethod] - public void GetLatestVersionTest() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var files = FFMpegDownloader.GetLatestVersion(); - Assert.IsTrue(files.Count == 3); - } - else - { - Assert.Inconclusive("This test is only for Windows"); - } - + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var fileNames = FFMpegDownloader.AutoDownloadFFMpeg(); + Assert.IsTrue(fileNames.Count == 1); + } + else + { + Assert.Inconclusive("This test is only for Windows"); + } + } + + [TestMethod] + public void GetLatestFFProbeTest() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var fileNames = FFMpegDownloader.AutoDownloadFFProbe(); + Assert.IsTrue(fileNames.Count == 1); + } + else + { + Assert.Inconclusive("This test is only for Windows"); + } + } + + [TestMethod] + public void GetLatestFFPlayTest() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + var fileNames = FFMpegDownloader.AutoDownloadFFPlay(); + Assert.IsTrue(fileNames.Count == 1); + } + else + { + Assert.Inconclusive("This test is only for Windows"); } } } diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index 7767683e..d6149e84 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -8,26 +8,95 @@ namespace FFMpegCore.Helpers; using System.Runtime.InteropServices; /// -/// Downloads the latest FFMpeg binaries from GitHub. Only supported for windows at the moment. +/// Downloads the latest FFMpeg suite binaries from GitHub. Only supported for windows at the moment. /// public class FFMpegDownloader // this class is built to be easily modified to support other platforms { - /// - /// List of URLs to download FFMpeg from. - /// - private static Dictionary FFMpegDownloadUrls = new() + private static Dictionary Windows64FFMpegDownloadUrls = new() { - { "windows", "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip" } + { FFMpegVersions.V4_4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.4.1/ffmpeg-4.4.1-win-64.zip"}, + { FFMpegVersions.V4_2_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-64.zip"}, + { FFMpegVersions.V4_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-64.zip"}, + { FFMpegVersions.V4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-64.zip"}, + { FFMpegVersions.V4_0, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-64.zip"}, + { FFMpegVersions.V3_4, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-64.zip"}, + { FFMpegVersions.V3_3, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-64.zip"}, + { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-64.zip"}, }; + + private static Dictionary Windows32FFMpegDownloadUrls = new() + { + { FFMpegVersions.V4_4_1, "https://example.com/" }, + { FFMpegVersions.V4_2_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-32.zip"}, + { FFMpegVersions.V4_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-32.zip"}, + { FFMpegVersions.V4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-32.zip"}, + { FFMpegVersions.V4_0, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-32.zip"}, + { FFMpegVersions.V3_4, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-32.zip"}, + { FFMpegVersions.V3_3, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-32.zip"}, + { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-32.zip"}, + }; + + public enum FFMpegVersions + { + V4_4_1, + V4_2_1, + V4_2, + V4_1, + V4_0, + V3_4, + V3_3, + V3_2 + } + + public static List AutoDownloadFFMpegSuite(FFMpegVersions version = FFMpegVersions.V4_4_1) + { + var files = AutoDownloadFFMpeg(version); + files.AddRange(AutoDownloadFFProbe(version)); + files.AddRange(AutoDownloadFFPlay(version)); + + return files; + } + + public static List AutoDownloadFFMpeg(FFMpegVersions version = FFMpegVersions.V4_4_1) + { + var url = Environment.Is64BitProcess + ? new Uri(Windows64FFMpegDownloadUrls[version]) + : new Uri(Windows32FFMpegDownloadUrls[version]); + + HasValidUri(url); + + Stream zipStream = DownloadZip(url); - public static List GetLatestVersion() + return ExtractAndSave(zipStream); + } + + public static List AutoDownloadFFProbe(FFMpegVersions version = FFMpegVersions.V4_4_1) { - var os = GetOSPlatform(); - var zipStream = DownloadFFMpeg(new Uri(FFMpegDownloadUrls[os])); + var url = Environment.Is64BitProcess + ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffprobe")) + : new Uri(Windows32FFMpegDownloadUrls[version].Replace("ffmpeg", "ffprobe")); + + HasValidUri(url); + + Stream zipStream = DownloadZip(url); + return ExtractAndSave(zipStream); } + + public static List AutoDownloadFFPlay(FFMpegVersions version = FFMpegVersions.V4_4_1) + { + var url = Environment.Is64BitProcess + ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffplay")) + : new Uri(Windows32FFMpegDownloadUrls[version].Replace("ffmpeg", "ffplay")); + + HasValidUri(url); + + Stream zipStream = DownloadZip(url); - private static MemoryStream DownloadFFMpeg(Uri address) + return ExtractAndSave(zipStream); + } + + private static MemoryStream DownloadZip(Uri address) { var client = new WebClient(); var zipStream = new MemoryStream(client.DownloadData(address)); @@ -51,14 +120,12 @@ private static List ExtractAndSave(Stream zipStream) return files; } - - private static string GetOSPlatform() + + private static void HasValidUri(Uri uri) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (uri.ToString() == "https://example.com/" || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return "windows"; + throw new PlatformNotSupportedException("The requested version of FFMpeg component is not available for your OS."); } - - throw new PlatformNotSupportedException("Auto download is only supported on Windows."); } } From 657ee5ff5d371487e950c75e141f220a568927ab Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Fri, 5 May 2023 01:21:53 -0600 Subject: [PATCH 03/17] Comments added --- FFMpegCore/Helpers/FFMpegDownloader.cs | 52 ++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index d6149e84..9d87001b 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -1,6 +1,4 @@ -using System.ComponentModel; -using System.Net; -using System.IO; +using System.Net; using System.IO.Compression; @@ -10,7 +8,7 @@ namespace FFMpegCore.Helpers; /// /// Downloads the latest FFMpeg suite binaries from GitHub. Only supported for windows at the moment. /// -public class FFMpegDownloader // this class is built to be easily modified to support other platforms +public class FFMpegDownloader { private static Dictionary Windows64FFMpegDownloadUrls = new() { @@ -26,7 +24,7 @@ public class FFMpegDownloader // this class is built to be easily modified to su private static Dictionary Windows32FFMpegDownloadUrls = new() { - { FFMpegVersions.V4_4_1, "https://example.com/" }, + { FFMpegVersions.V4_4_1, "" }, { FFMpegVersions.V4_2_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-32.zip"}, { FFMpegVersions.V4_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-32.zip"}, { FFMpegVersions.V4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-32.zip"}, @@ -36,6 +34,9 @@ public class FFMpegDownloader // this class is built to be easily modified to su { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-32.zip"}, }; + /// + /// Supported FFMpeg versions + /// public enum FFMpegVersions { V4_4_1, @@ -48,6 +49,11 @@ public enum FFMpegVersions V3_2 } + /// + /// Downloads the latest FFMpeg suite binaries to bin directory. + /// + /// + /// public static List AutoDownloadFFMpegSuite(FFMpegVersions version = FFMpegVersions.V4_4_1) { var files = AutoDownloadFFMpeg(version); @@ -57,6 +63,11 @@ public static List AutoDownloadFFMpegSuite(FFMpegVersions version = FFMp return files; } + /// + /// Downloads the latest FFMpeg binaries to bin directory. + /// + /// + /// public static List AutoDownloadFFMpeg(FFMpegVersions version = FFMpegVersions.V4_4_1) { var url = Environment.Is64BitProcess @@ -70,6 +81,11 @@ public static List AutoDownloadFFMpeg(FFMpegVersions version = FFMpegVer return ExtractAndSave(zipStream); } + /// + /// Downloads the latest FFProbe binaries to bin directory. + /// + /// + /// public static List AutoDownloadFFProbe(FFMpegVersions version = FFMpegVersions.V4_4_1) { var url = Environment.Is64BitProcess @@ -83,6 +99,11 @@ public static List AutoDownloadFFProbe(FFMpegVersions version = FFMpegVe return ExtractAndSave(zipStream); } + /// + /// Downloads the latest FFPlay binaries to bin directory. + /// + /// + /// public static List AutoDownloadFFPlay(FFMpegVersions version = FFMpegVersions.V4_4_1) { var url = Environment.Is64BitProcess @@ -96,6 +117,11 @@ public static List AutoDownloadFFPlay(FFMpegVersions version = FFMpegVer return ExtractAndSave(zipStream); } + /// + /// Downloads the zip file from the given url. + /// + /// + /// private static MemoryStream DownloadZip(Uri address) { var client = new WebClient(); @@ -105,13 +131,18 @@ private static MemoryStream DownloadZip(Uri address) return zipStream; } + /// + /// Extracts the zip file and saves the binaries to bin directory. + /// + /// + /// private static List ExtractAndSave(Stream zipStream) { using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read); List files = new(); foreach (var entry in archive.Entries) { - if (entry.Name is "ffmpeg.exe" or "ffmpeg" or "ffprobe.exe") + if (entry.Name is "ffmpeg.exe" or "ffmpeg" or "ffprobe.exe" or "ffplay.exe" or "ffplay") // only extract the binaries { entry.ExtractToFile(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name), true); files.Add(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name)); @@ -121,11 +152,16 @@ private static List ExtractAndSave(Stream zipStream) return files; } + /// + /// Checks if the given uri is valid. + /// + /// + /// private static void HasValidUri(Uri uri) { - if (uri.ToString() == "https://example.com/" || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (uri.ToString() == "" || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - throw new PlatformNotSupportedException("The requested version of FFMpeg component is not available for your OS."); + throw new PlatformNotSupportedException("The requested version of FFMpeg component is not available for your OS/System."); } } } From d68ce8e953f9e914e899ace85b32058b62bfe734 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Fri, 5 May 2023 01:30:52 -0600 Subject: [PATCH 04/17] Methods renamed to remove auto prefix --- FFMpegCore.Test/DownloaderTests.cs | 8 ++++---- FFMpegCore/Helpers/FFMpegDownloader.cs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index 2d968ad2..d0f1f557 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -12,7 +12,7 @@ public void GetLatestSuiteTest() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var fileNames = FFMpegDownloader.AutoDownloadFFMpegSuite(); + var fileNames = FFMpegDownloader.DownloadFFMpegSuite(); Assert.IsTrue(fileNames.Count == 3); } else @@ -26,7 +26,7 @@ public void GetLatestFFMpegTest() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var fileNames = FFMpegDownloader.AutoDownloadFFMpeg(); + var fileNames = FFMpegDownloader.DownloadFFMpeg(); Assert.IsTrue(fileNames.Count == 1); } else @@ -40,7 +40,7 @@ public void GetLatestFFProbeTest() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var fileNames = FFMpegDownloader.AutoDownloadFFProbe(); + var fileNames = FFMpegDownloader.DownloadFFProbe(); Assert.IsTrue(fileNames.Count == 1); } else @@ -54,7 +54,7 @@ public void GetLatestFFPlayTest() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var fileNames = FFMpegDownloader.AutoDownloadFFPlay(); + var fileNames = FFMpegDownloader.DownloadFFPlay(); Assert.IsTrue(fileNames.Count == 1); } else diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index 9d87001b..89b3d4ca 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -53,12 +53,12 @@ public enum FFMpegVersions /// Downloads the latest FFMpeg suite binaries to bin directory. /// /// - /// - public static List AutoDownloadFFMpegSuite(FFMpegVersions version = FFMpegVersions.V4_4_1) + /// Names of the binary that was saved to bin directory + public static List DownloadFFMpegSuite(FFMpegVersions version = FFMpegVersions.V4_4_1) { - var files = AutoDownloadFFMpeg(version); - files.AddRange(AutoDownloadFFProbe(version)); - files.AddRange(AutoDownloadFFPlay(version)); + var files = DownloadFFMpeg(version); + files.AddRange(DownloadFFProbe(version)); + files.AddRange(DownloadFFPlay(version)); return files; } @@ -68,7 +68,7 @@ public static List AutoDownloadFFMpegSuite(FFMpegVersions version = FFMp /// /// /// - public static List AutoDownloadFFMpeg(FFMpegVersions version = FFMpegVersions.V4_4_1) + public static List DownloadFFMpeg(FFMpegVersions version = FFMpegVersions.V4_4_1) { var url = Environment.Is64BitProcess ? new Uri(Windows64FFMpegDownloadUrls[version]) @@ -86,7 +86,7 @@ public static List AutoDownloadFFMpeg(FFMpegVersions version = FFMpegVer /// /// /// - public static List AutoDownloadFFProbe(FFMpegVersions version = FFMpegVersions.V4_4_1) + public static List DownloadFFProbe(FFMpegVersions version = FFMpegVersions.V4_4_1) { var url = Environment.Is64BitProcess ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffprobe")) @@ -104,7 +104,7 @@ public static List AutoDownloadFFProbe(FFMpegVersions version = FFMpegVe /// /// /// - public static List AutoDownloadFFPlay(FFMpegVersions version = FFMpegVersions.V4_4_1) + public static List DownloadFFPlay(FFMpegVersions version = FFMpegVersions.V4_4_1) { var url = Environment.Is64BitProcess ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffplay")) From debb868b38ef11deee4335bc7d37a2f75bc9e333 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Fri, 5 May 2023 01:34:21 -0600 Subject: [PATCH 05/17] README.md updated to include ffmpegdownloader usage --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 365d0be2..74876a76 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,19 @@ 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();` + +Or you can download only the desired binary using `FFMpegDownloader.DownloadFFMpeg()`, `FFMpegDownloader.DownloadFFProbe()`, `FFMpegDownloader.DownloadFFPlay()`. + +| OS | Support | +|---------|:-------------------------------------------------:| +| Windows | x64 Fully Supported, x86 Up to version V4.2.1 | +| Mac OSX | NOT YET | +| Linux | NOT YET | + + +## Manual Installation If you prefer to manually download them, visit [ffbinaries](https://ffbinaries.com/downloads) or [zeranoe Windows builds](https://ffmpeg.zeranoe.com/builds/). ### Windows (using choco) From a647f440296dc5d668d10ca6b08bbda033b32998 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Fri, 5 May 2023 01:47:08 -0600 Subject: [PATCH 06/17] refactoring and reformatting --- FFMpegCore/Helpers/FFMpegDownloader.cs | 128 +++++++++++++++++-------- 1 file changed, 88 insertions(+), 40 deletions(-) diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index 89b3d4ca..fef53b3b 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -1,39 +1,83 @@ using System.Net; using System.IO.Compression; - +using System.Runtime.InteropServices; namespace FFMpegCore.Helpers; -using System.Runtime.InteropServices; /// /// Downloads the latest FFMpeg suite binaries from GitHub. Only supported for windows at the moment. /// public class FFMpegDownloader { - private static Dictionary Windows64FFMpegDownloadUrls = new() + private static readonly Dictionary Windows64FFMpegDownloadUrls = new() { - { FFMpegVersions.V4_4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.4.1/ffmpeg-4.4.1-win-64.zip"}, - { FFMpegVersions.V4_2_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-64.zip"}, - { FFMpegVersions.V4_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-64.zip"}, - { FFMpegVersions.V4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-64.zip"}, - { FFMpegVersions.V4_0, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-64.zip"}, - { FFMpegVersions.V3_4, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-64.zip"}, - { FFMpegVersions.V3_3, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-64.zip"}, - { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-64.zip"}, + { + FFMpegVersions.V4_4_1, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.4.1/ffmpeg-4.4.1-win-64.zip" + }, + { + FFMpegVersions.V4_2_1, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-64.zip" + }, + { + FFMpegVersions.V4_2, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-64.zip" + }, + { + FFMpegVersions.V4_1, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-64.zip" + }, + { + FFMpegVersions.V4_0, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-64.zip" + }, + { + FFMpegVersions.V3_4, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-64.zip" + }, + { + FFMpegVersions.V3_3, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-64.zip" + }, + { + FFMpegVersions.V3_2, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-64.zip" + }, }; - - private static Dictionary Windows32FFMpegDownloadUrls = new() + + private static readonly Dictionary Windows32FFMpegDownloadUrls = new() { { FFMpegVersions.V4_4_1, "" }, - { FFMpegVersions.V4_2_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-32.zip"}, - { FFMpegVersions.V4_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-32.zip"}, - { FFMpegVersions.V4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-32.zip"}, - { FFMpegVersions.V4_0, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-32.zip"}, - { FFMpegVersions.V3_4, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-32.zip"}, - { FFMpegVersions.V3_3, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-32.zip"}, - { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-32.zip"}, + { + FFMpegVersions.V4_2_1, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-32.zip" + }, + { + FFMpegVersions.V4_2, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-32.zip" + }, + { + FFMpegVersions.V4_1, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-32.zip" + }, + { + FFMpegVersions.V4_0, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-32.zip" + }, + { + FFMpegVersions.V3_4, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-32.zip" + }, + { + FFMpegVersions.V3_3, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-32.zip" + }, + { + FFMpegVersions.V3_2, + "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-32.zip" + }, }; - + /// /// Supported FFMpeg versions /// @@ -59,7 +103,7 @@ public static List DownloadFFMpegSuite(FFMpegVersions version = FFMpegVe var files = DownloadFFMpeg(version); files.AddRange(DownloadFFProbe(version)); files.AddRange(DownloadFFPlay(version)); - + return files; } @@ -73,14 +117,10 @@ public static List DownloadFFMpeg(FFMpegVersions version = FFMpegVersion var url = Environment.Is64BitProcess ? new Uri(Windows64FFMpegDownloadUrls[version]) : new Uri(Windows32FFMpegDownloadUrls[version]); - - HasValidUri(url); - Stream zipStream = DownloadZip(url); - - return ExtractAndSave(zipStream); + return DownloadAndSave(url); } - + /// /// Downloads the latest FFProbe binaries to bin directory. /// @@ -91,14 +131,10 @@ public static List DownloadFFProbe(FFMpegVersions version = FFMpegVersio var url = Environment.Is64BitProcess ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffprobe")) : new Uri(Windows32FFMpegDownloadUrls[version].Replace("ffmpeg", "ffprobe")); - - HasValidUri(url); - - Stream zipStream = DownloadZip(url); - return ExtractAndSave(zipStream); + return DownloadAndSave(url); } - + /// /// Downloads the latest FFPlay binaries to bin directory. /// @@ -109,12 +145,22 @@ public static List DownloadFFPlay(FFMpegVersions version = FFMpegVersion var url = Environment.Is64BitProcess ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffplay")) : new Uri(Windows32FFMpegDownloadUrls[version].Replace("ffmpeg", "ffplay")); - + + return DownloadAndSave(url); + } + + /// + /// Downloads the zip file from the given url and saves the binaries to bin directory. + /// + /// + /// + private static List DownloadAndSave(Uri url) + { HasValidUri(url); Stream zipStream = DownloadZip(url); - return ExtractAndSave(zipStream); + return ExtractZip(zipStream); } /// @@ -130,19 +176,20 @@ private static MemoryStream DownloadZip(Uri address) return zipStream; } - + /// /// Extracts the zip file and saves the binaries to bin directory. /// /// /// - private static List ExtractAndSave(Stream zipStream) + private static List ExtractZip(Stream zipStream) { using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read); List files = new(); foreach (var entry in archive.Entries) { - if (entry.Name is "ffmpeg.exe" or "ffmpeg" or "ffprobe.exe" or "ffplay.exe" or "ffplay") // only extract the binaries + if (entry.Name is "ffmpeg.exe" or "ffmpeg" or "ffprobe.exe" or "ffplay.exe" + or "ffplay") // only extract the binaries { entry.ExtractToFile(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name), true); files.Add(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name)); @@ -161,7 +208,8 @@ private static void HasValidUri(Uri uri) { if (uri.ToString() == "" || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - throw new PlatformNotSupportedException("The requested version of FFMpeg component is not available for your OS/System."); + throw new PlatformNotSupportedException( + "The requested version of FFMpeg component is not available for your OS/System."); } } } From 463fb9bf6b9153e945d433f8ca2349ead0cf4e2f Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Fri, 5 May 2023 01:54:50 -0600 Subject: [PATCH 07/17] Reformatted to fix lint error --- FFMpegCore.Test/DownloaderTests.cs | 6 +-- FFMpegCore/Helpers/FFMpegDownloader.cs | 56 +++++++++++++------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index d0f1f557..52c17806 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -20,7 +20,7 @@ public void GetLatestSuiteTest() Assert.Inconclusive("This test is only for Windows"); } } - + [TestMethod] public void GetLatestFFMpegTest() { @@ -34,7 +34,7 @@ public void GetLatestFFMpegTest() Assert.Inconclusive("This test is only for Windows"); } } - + [TestMethod] public void GetLatestFFProbeTest() { @@ -48,7 +48,7 @@ public void GetLatestFFProbeTest() Assert.Inconclusive("This test is only for Windows"); } } - + [TestMethod] public void GetLatestFFPlayTest() { diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index fef53b3b..67055405 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -1,14 +1,29 @@ -using System.Net; -using System.IO.Compression; +using System.IO.Compression; +using System.Net; using System.Runtime.InteropServices; namespace FFMpegCore.Helpers; /// -/// Downloads the latest FFMpeg suite binaries from GitHub. Only supported for windows at the moment. +/// Downloads the latest FFMpeg suite binaries from GitHub. Only supported for windows at the moment. /// public class FFMpegDownloader { + /// + /// Supported FFMpeg versions + /// + public enum FFMpegVersions + { + V4_4_1, + V4_2_1, + V4_2, + V4_1, + V4_0, + V3_4, + V3_3, + V3_2 + } + private static readonly Dictionary Windows64FFMpegDownloadUrls = new() { { @@ -42,7 +57,7 @@ public class FFMpegDownloader { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-64.zip" - }, + } }; private static readonly Dictionary Windows32FFMpegDownloadUrls = new() @@ -75,26 +90,11 @@ public class FFMpegDownloader { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-32.zip" - }, + } }; /// - /// Supported FFMpeg versions - /// - public enum FFMpegVersions - { - V4_4_1, - V4_2_1, - V4_2, - V4_1, - V4_0, - V3_4, - V3_3, - V3_2 - } - - /// - /// Downloads the latest FFMpeg suite binaries to bin directory. + /// Downloads the latest FFMpeg suite binaries to bin directory. /// /// /// Names of the binary that was saved to bin directory @@ -108,7 +108,7 @@ public static List DownloadFFMpegSuite(FFMpegVersions version = FFMpegVe } /// - /// Downloads the latest FFMpeg binaries to bin directory. + /// Downloads the latest FFMpeg binaries to bin directory. /// /// /// @@ -122,7 +122,7 @@ public static List DownloadFFMpeg(FFMpegVersions version = FFMpegVersion } /// - /// Downloads the latest FFProbe binaries to bin directory. + /// Downloads the latest FFProbe binaries to bin directory. /// /// /// @@ -136,7 +136,7 @@ public static List DownloadFFProbe(FFMpegVersions version = FFMpegVersio } /// - /// Downloads the latest FFPlay binaries to bin directory. + /// Downloads the latest FFPlay binaries to bin directory. /// /// /// @@ -150,7 +150,7 @@ public static List DownloadFFPlay(FFMpegVersions version = FFMpegVersion } /// - /// Downloads the zip file from the given url and saves the binaries to bin directory. + /// Downloads the zip file from the given url and saves the binaries to bin directory. /// /// /// @@ -164,7 +164,7 @@ private static List DownloadAndSave(Uri url) } /// - /// Downloads the zip file from the given url. + /// Downloads the zip file from the given url. /// /// /// @@ -178,7 +178,7 @@ private static MemoryStream DownloadZip(Uri address) } /// - /// Extracts the zip file and saves the binaries to bin directory. + /// Extracts the zip file and saves the binaries to bin directory. /// /// /// @@ -200,7 +200,7 @@ private static List ExtractZip(Stream zipStream) } /// - /// Checks if the given uri is valid. + /// Checks if the given uri is valid. /// /// /// From da7d1fafed127d1f4c89f39d191e2a87f7e756b5 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Wed, 6 Sep 2023 01:25:51 -0600 Subject: [PATCH 08/17] support added for linux, macos win32, win64, lnx32, lnx64, lnx-armhf, lnx-armel, lnx-arm64, osx64 --- FFMpegCore.Test/DownloaderTests.cs | 61 +----- FFMpegCore/Helpers/FFMpegDownloader.cs | 275 +++++++++++++++++-------- 2 files changed, 204 insertions(+), 132 deletions(-) diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index 2d968ad2..c677d5da 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -1,5 +1,4 @@ -using System.Runtime.InteropServices; -using FFMpegCore.Helpers; +using FFMpegCore.Helpers; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace FFMpegCore.Test; @@ -8,58 +7,18 @@ namespace FFMpegCore.Test; public class DownloaderTests { [TestMethod] - public void GetLatestSuiteTest() + public void GetAllLatestSuiteTest() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var fileNames = FFMpegDownloader.AutoDownloadFFMpegSuite(); - Assert.IsTrue(fileNames.Count == 3); - } - else - { - Assert.Inconclusive("This test is only for Windows"); - } + var binaries = FFMpegDownloader.DownloadFFMpegSuite(binaries: FFMpegDownloader.FFMpegBinaries.FFProbe | + FFMpegDownloader.FFMpegBinaries.FFMpeg | + FFMpegDownloader.FFMpegBinaries.FFPlay).Result; + Assert.IsTrue(binaries.Count >= 2); // many platforms have only ffmpeg and ffprobe } - - [TestMethod] - public void GetLatestFFMpegTest() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var fileNames = FFMpegDownloader.AutoDownloadFFMpeg(); - Assert.IsTrue(fileNames.Count == 1); - } - else - { - Assert.Inconclusive("This test is only for Windows"); - } - } - - [TestMethod] - public void GetLatestFFProbeTest() - { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var fileNames = FFMpegDownloader.AutoDownloadFFProbe(); - Assert.IsTrue(fileNames.Count == 1); - } - else - { - Assert.Inconclusive("This test is only for Windows"); - } - } - + [TestMethod] - public void GetLatestFFPlayTest() + public void GetSpecificVersionTest() { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - var fileNames = FFMpegDownloader.AutoDownloadFFPlay(); - Assert.IsTrue(fileNames.Count == 1); - } - else - { - Assert.Inconclusive("This test is only for Windows"); - } + var binaries = FFMpegDownloader.DownloadFFMpegSuite(FFMpegDownloader.FFMpegVersions.V4_0).Result; + Assert.IsTrue(binaries.Count == 2); } } diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index d6149e84..c07a30ef 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -1,43 +1,38 @@ -using System.ComponentModel; +using System.IO.Compression; using System.Net; -using System.IO; -using System.IO.Compression; - +using System.Runtime.InteropServices; +using System.Text.Json; +using System.Text.Json.Serialization; namespace FFMpegCore.Helpers; -using System.Runtime.InteropServices; /// -/// Downloads the latest FFMpeg suite binaries from GitHub. Only supported for windows at the moment. +/// Downloads the latest FFMpeg suite binaries from ffbinaries.com. /// -public class FFMpegDownloader // this class is built to be easily modified to support other platforms +public class FFMpegDownloader { - private static Dictionary Windows64FFMpegDownloadUrls = new() - { - { FFMpegVersions.V4_4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.4.1/ffmpeg-4.4.1-win-64.zip"}, - { FFMpegVersions.V4_2_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-64.zip"}, - { FFMpegVersions.V4_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-64.zip"}, - { FFMpegVersions.V4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-64.zip"}, - { FFMpegVersions.V4_0, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-64.zip"}, - { FFMpegVersions.V3_4, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-64.zip"}, - { FFMpegVersions.V3_3, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-64.zip"}, - { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-64.zip"}, - }; - - private static Dictionary Windows32FFMpegDownloadUrls = new() + [Flags] + public enum FFMpegBinaries : ushort { - { FFMpegVersions.V4_4_1, "https://example.com/" }, - { FFMpegVersions.V4_2_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-win-32.zip"}, - { FFMpegVersions.V4_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.2/ffmpeg-4.2-win-32.zip"}, - { FFMpegVersions.V4_1, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.1/ffmpeg-4.1-win-32.zip"}, - { FFMpegVersions.V4_0, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v4.0/ffmpeg-4.0.1-win-32.zip"}, - { FFMpegVersions.V3_4, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.4/ffmpeg-3.4-win-32.zip"}, - { FFMpegVersions.V3_3, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.3/ffmpeg-3.3.4-win-32.zip"}, - { FFMpegVersions.V3_2, "https://github.com/ffbinaries/ffbinaries-prebuilt/releases/download/v3.2/ffmpeg-3.2-win-32.zip"}, - }; - - public enum FFMpegVersions + /// + /// FFMpeg binary + /// + FFMpeg, + + /// + /// FFProbe binary + /// + FFProbe, + + /// + /// FFPlay binary + /// + FFPlay + } + + public enum FFMpegVersions : ushort { + Latest, V4_4_1, V4_2_1, V4_2, @@ -48,70 +43,71 @@ public enum FFMpegVersions V3_2 } - public static List AutoDownloadFFMpegSuite(FFMpegVersions version = FFMpegVersions.V4_4_1) + /// + /// Download the latest FFMpeg suite binaries for current platform + /// + /// used to explicitly state the version of binary you want to download + /// used to explicitly state the binary you want to download + /// a list of the binaries that have been successfully downloaded + public static async Task> DownloadFFMpegSuite(FFMpegVersions version = FFMpegVersions.Latest, + FFMpegBinaries binaries = FFMpegBinaries.FFMpeg | FFMpegBinaries.FFProbe) { - var files = AutoDownloadFFMpeg(version); - files.AddRange(AutoDownloadFFProbe(version)); - files.AddRange(AutoDownloadFFPlay(version)); - - return files; - } + var versionInfo = await GetVersionInfo(version); + var downloadInfo = versionInfo.BinaryInfo?.GetCompatibleDownloadInfo() ?? + throw new FFMpegDownloaderException("Failed to get compatible download info"); - public static List AutoDownloadFFMpeg(FFMpegVersions version = FFMpegVersions.V4_4_1) - { - var url = Environment.Is64BitProcess - ? new Uri(Windows64FFMpegDownloadUrls[version]) - : new Uri(Windows32FFMpegDownloadUrls[version]); - - HasValidUri(url); + var successList = new List(); - Stream zipStream = DownloadZip(url); + // if ffmpeg is selected + if (binaries.HasFlag(FFMpegBinaries.FFMpeg) && downloadInfo.FFMpeg is not null) + { + var zipStream = DownloadFileAsSteam(new Uri(downloadInfo.FFMpeg)); + successList.AddRange(ExtractZipAndSave(zipStream)); + } - return ExtractAndSave(zipStream); - } - - public static List AutoDownloadFFProbe(FFMpegVersions version = FFMpegVersions.V4_4_1) - { - var url = Environment.Is64BitProcess - ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffprobe")) - : new Uri(Windows32FFMpegDownloadUrls[version].Replace("ffmpeg", "ffprobe")); - - HasValidUri(url); - - Stream zipStream = DownloadZip(url); - - return ExtractAndSave(zipStream); - } - - public static List AutoDownloadFFPlay(FFMpegVersions version = FFMpegVersions.V4_4_1) - { - var url = Environment.Is64BitProcess - ? new Uri(Windows64FFMpegDownloadUrls[version].Replace("ffmpeg", "ffplay")) - : new Uri(Windows32FFMpegDownloadUrls[version].Replace("ffmpeg", "ffplay")); - - HasValidUri(url); + // if ffprobe is selected + if (binaries.HasFlag(FFMpegBinaries.FFProbe) && downloadInfo.FFProbe is not null) + { + var zipStream = DownloadFileAsSteam(new Uri(downloadInfo.FFProbe)); + successList.AddRange(ExtractZipAndSave(zipStream)); + } - Stream zipStream = DownloadZip(url); + // if ffplay is selected + if (binaries.HasFlag(FFMpegBinaries.FFPlay) && downloadInfo.FFPlay is not null) + { + var zipStream = DownloadFileAsSteam(new Uri(downloadInfo.FFPlay)); + successList.AddRange(ExtractZipAndSave(zipStream)); + } - return ExtractAndSave(zipStream); + return successList; } - private static MemoryStream DownloadZip(Uri address) + /// + /// Download file from uri + /// + /// uri of the file + /// + private static MemoryStream DownloadFileAsSteam(Uri address) { var client = new WebClient(); - var zipStream = new MemoryStream(client.DownloadData(address)); - zipStream.Position = 0; + var fileStream = new MemoryStream(client.DownloadData(address)); + fileStream.Position = 0; - return zipStream; + return fileStream; } - - private static List ExtractAndSave(Stream zipStream) + + /// + /// Extracts the binaries from the zip stream and saves them to the current binary folder + /// + /// steam of the zip file + /// + private static List ExtractZipAndSave(Stream zipStream) { using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read); List files = new(); foreach (var entry in archive.Entries) { - if (entry.Name is "ffmpeg.exe" or "ffmpeg" or "ffprobe.exe") + if (entry.Name is "ffmpeg" or "ffmpeg.exe" or "ffprobe.exe" or "ffprobe" or "ffplay.exe" or "ffplay") { entry.ExtractToFile(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name), true); files.Add(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name)); @@ -121,11 +117,128 @@ private static List ExtractAndSave(Stream zipStream) return files; } - private static void HasValidUri(Uri uri) + #region FFbinaries api + + private class DownloadInfo + { + [JsonPropertyName("ffmpeg")] public string? FFMpeg { get; } + + [JsonPropertyName("ffprobe")] public string? FFProbe { get; } + + [JsonPropertyName("ffplay")] public string? FFPlay { get; } + } + + private class BinaryInfo + { + [JsonPropertyName("windows-64")] public DownloadInfo? Windows64 { get; } + + [JsonPropertyName("windows-32")] public DownloadInfo? Windows32 { get; } + + [JsonPropertyName("linux-32")] public DownloadInfo? Linux32 { get; set; } + + [JsonPropertyName("linux-64")] public DownloadInfo? Linux64 { get; } + + [JsonPropertyName("linux-armhf")] public DownloadInfo? LinuxArmhf { get; } + + [JsonPropertyName("linux-armel")] public DownloadInfo? LinuxArmel { get; set; } + + [JsonPropertyName("linux-arm64")] public DownloadInfo? LinuxArm64 { get; } + + [JsonPropertyName("osx-64")] public DownloadInfo? Osx64 { get; } + + public DownloadInfo? GetCompatibleDownloadInfo() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return RuntimeInformation.OSArchitecture == Architecture.X64 ? Windows64 : Windows32; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + return RuntimeInformation.OSArchitecture switch + { + Architecture.X64 => Linux64, + Architecture.Arm => LinuxArmhf, + Architecture.Arm64 => LinuxArm64, + _ => throw new PlatformNotSupportedException("Unsupported Linux architecture") + }; + } + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + return Osx64; + } + + throw new PlatformNotSupportedException("Unsupported OS"); + } + } + + private class VersionInfo + { + [JsonPropertyName("version")] public string? Version { get; set; } + + [JsonPropertyName("permalink")] public string? Permalink { get; set; } + + [JsonPropertyName("bin")] public BinaryInfo? BinaryInfo { get; set; } + } + + private static readonly Dictionary FFBinariesAPIs = new() { - if (uri.ToString() == "https://example.com/" || !RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { FFMpegVersions.Latest, "https://ffbinaries.com/api/v1/version/latest" }, + { FFMpegVersions.V4_4_1, "https://ffbinaries.com/api/v1/version/4.4.1" }, + { FFMpegVersions.V4_2_1, "https://ffbinaries.com/api/v1/version/4.2.1" }, + { FFMpegVersions.V4_2, "https://ffbinaries.com/api/v1/version/4.2" }, + { FFMpegVersions.V4_1, "https://ffbinaries.com/api/v1/version/4.1" }, + { FFMpegVersions.V4_0, "https://ffbinaries.com/api/v1/version/4.0" }, + { FFMpegVersions.V3_4, "https://ffbinaries.com/api/v1/version/3.4" }, + { FFMpegVersions.V3_3, "https://ffbinaries.com/api/v1/version/3.3" }, + { FFMpegVersions.V3_2, "https://ffbinaries.com/api/v1/version/3.2" } + }; + + /// + /// Get version info from ffbinaries.com + /// + /// use to explicitly state the version of ffmpeg you want + /// + /// + private static async Task GetVersionInfo(FFMpegVersions version) + { + if (!FFBinariesAPIs.TryGetValue(version, out var versionUri)) + { + throw new FFMpegDownloaderException($"Invalid version selected: {version}", "contact dev"); + } + + HttpClient client = new(); + var response = await client.GetAsync(versionUri); + + if (!response.IsSuccessStatusCode) { - throw new PlatformNotSupportedException("The requested version of FFMpeg component is not available for your OS."); + throw new FFMpegDownloaderException($"Failed to get version info from {versionUri}", "network error"); } + + var jsonString = await response.Content.ReadAsStringAsync(); + var versionInfo = JsonSerializer.Deserialize(jsonString); + + return versionInfo ?? + throw new FFMpegDownloaderException($"Failed to deserialize version info from {versionUri}", jsonString); } + + #endregion +} + +/// +/// Custom exception for FFMpegDownloader +/// +public class FFMpegDownloaderException : Exception +{ + public FFMpegDownloaderException(string message) : base(message) + { + } + + public FFMpegDownloaderException(string message, string detail) : base(message) + { + Detail = detail; + } + + public string Detail { get; set; } = ""; } From df8d97ebbbb7f3617ce4bc9850ec408449ead186 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Wed, 6 Sep 2023 13:19:02 -0600 Subject: [PATCH 09/17] allow os and architecture overrider --- FFMpegCore/Helpers/FFMpegDownloader.cs | 102 +++++++++++++++++-------- 1 file changed, 69 insertions(+), 33 deletions(-) diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index c07a30ef..f465f1b1 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -14,19 +14,8 @@ public class FFMpegDownloader [Flags] public enum FFMpegBinaries : ushort { - /// - /// FFMpeg binary - /// FFMpeg, - - /// - /// FFProbe binary - /// FFProbe, - - /// - /// FFPlay binary - /// FFPlay } @@ -43,17 +32,32 @@ public enum FFMpegVersions : ushort V3_2 } + public enum PlatformOverride : short + { + Windows64, + Windows32, + Linux64, + Linux32, + LinuxArmhf, + LinuxArmel, + LinuxArm64, + Osx64 + } + /// /// Download the latest FFMpeg suite binaries for current platform /// /// used to explicitly state the version of binary you want to download - /// used to explicitly state the binary you want to download + /// used to explicitly state the binaries you want to download (ffmpeg, ffprobe, ffplay) + /// used to explicitly state the os and architecture you want to download /// a list of the binaries that have been successfully downloaded - public static async Task> DownloadFFMpegSuite(FFMpegVersions version = FFMpegVersions.Latest, - FFMpegBinaries binaries = FFMpegBinaries.FFMpeg | FFMpegBinaries.FFProbe) + public static async Task> DownloadFFMpegSuite( + FFMpegVersions version = FFMpegVersions.Latest, + FFMpegBinaries binaries = FFMpegBinaries.FFMpeg | FFMpegBinaries.FFProbe, + PlatformOverride? platformOverride = null) { var versionInfo = await GetVersionInfo(version); - var downloadInfo = versionInfo.BinaryInfo?.GetCompatibleDownloadInfo() ?? + var downloadInfo = versionInfo.BinaryInfo?.GetCompatibleDownloadInfo(platformOverride) ?? throw new FFMpegDownloaderException("Failed to get compatible download info"); var successList = new List(); @@ -81,7 +85,7 @@ public static async Task> DownloadFFMpegSuite(FFMpegVersions versio return successList; } - + /// /// Download file from uri /// @@ -101,7 +105,7 @@ private static MemoryStream DownloadFileAsSteam(Uri address) /// /// steam of the zip file /// - private static List ExtractZipAndSave(Stream zipStream) + private static IEnumerable ExtractZipAndSave(Stream zipStream) { using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read); List files = new(); @@ -121,33 +125,64 @@ private static List ExtractZipAndSave(Stream zipStream) private class DownloadInfo { - [JsonPropertyName("ffmpeg")] public string? FFMpeg { get; } + [JsonPropertyName("ffmpeg")] public string? FFMpeg { get; set; } - [JsonPropertyName("ffprobe")] public string? FFProbe { get; } + [JsonPropertyName("ffprobe")] public string? FFProbe { get; set; } - [JsonPropertyName("ffplay")] public string? FFPlay { get; } + [JsonPropertyName("ffplay")] public string? FFPlay { get; set; } } private class BinaryInfo { - [JsonPropertyName("windows-64")] public DownloadInfo? Windows64 { get; } + [JsonPropertyName("windows-64")] + public DownloadInfo? Windows64 { get; set; } - [JsonPropertyName("windows-32")] public DownloadInfo? Windows32 { get; } + [JsonPropertyName("windows-32")] + public DownloadInfo? Windows32 { get; set; } - [JsonPropertyName("linux-32")] public DownloadInfo? Linux32 { get; set; } + [JsonPropertyName("linux-32")] + public DownloadInfo? Linux32 { get; set; } - [JsonPropertyName("linux-64")] public DownloadInfo? Linux64 { get; } + [JsonPropertyName("linux-64")] + public DownloadInfo? Linux64 { get; set; } - [JsonPropertyName("linux-armhf")] public DownloadInfo? LinuxArmhf { get; } + [JsonPropertyName("linux-armhf")] + public DownloadInfo? LinuxArmhf { get; set; } - [JsonPropertyName("linux-armel")] public DownloadInfo? LinuxArmel { get; set; } + [JsonPropertyName("linux-armel")] + public DownloadInfo? LinuxArmel { get; set; } - [JsonPropertyName("linux-arm64")] public DownloadInfo? LinuxArm64 { get; } + [JsonPropertyName("linux-arm64")] + public DownloadInfo? LinuxArm64 { get; set; } - [JsonPropertyName("osx-64")] public DownloadInfo? Osx64 { get; } + [JsonPropertyName("osx-64")] + public DownloadInfo? Osx64 { get; set; } - public DownloadInfo? GetCompatibleDownloadInfo() + /// + /// Automatically get the compatible download info for current os and architecture + /// + /// + /// + /// + /// + public DownloadInfo? GetCompatibleDownloadInfo(PlatformOverride? platformOverride = null) { + if (platformOverride is not null) + { + return platformOverride switch + { + PlatformOverride.Windows64 => Windows64, + PlatformOverride.Windows32 => Windows32, + PlatformOverride.Linux64 => Linux64, + PlatformOverride.Linux32 => Linux32, + PlatformOverride.LinuxArmhf => LinuxArmhf, + PlatformOverride.LinuxArmel => LinuxArmel, + PlatformOverride.LinuxArm64 => LinuxArm64, + PlatformOverride.Osx64 => Osx64, + _ => throw new ArgumentOutOfRangeException(nameof(platformOverride), platformOverride, null) + }; + } + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { return RuntimeInformation.OSArchitecture == Architecture.X64 ? Windows64 : Windows32; @@ -157,10 +192,11 @@ private class BinaryInfo { return RuntimeInformation.OSArchitecture switch { + Architecture.X86 => Linux32, Architecture.X64 => Linux64, Architecture.Arm => LinuxArmhf, Architecture.Arm64 => LinuxArm64, - _ => throw new PlatformNotSupportedException("Unsupported Linux architecture") + _ => LinuxArmel }; } @@ -169,7 +205,7 @@ private class BinaryInfo return Osx64; } - throw new PlatformNotSupportedException("Unsupported OS"); + throw new PlatformNotSupportedException("Unsupported OS or Architecture"); } } @@ -182,7 +218,7 @@ private class VersionInfo [JsonPropertyName("bin")] public BinaryInfo? BinaryInfo { get; set; } } - private static readonly Dictionary FFBinariesAPIs = new() + private static readonly Dictionary _FFBinariesAPIs = new() { { FFMpegVersions.Latest, "https://ffbinaries.com/api/v1/version/latest" }, { FFMpegVersions.V4_4_1, "https://ffbinaries.com/api/v1/version/4.4.1" }, @@ -203,7 +239,7 @@ private class VersionInfo /// private static async Task GetVersionInfo(FFMpegVersions version) { - if (!FFBinariesAPIs.TryGetValue(version, out var versionUri)) + if (!_FFBinariesAPIs.TryGetValue(version, out var versionUri)) { throw new FFMpegDownloaderException($"Invalid version selected: {version}", "contact dev"); } From 937db76e0067c143866af2629642d63c23433332 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Wed, 6 Sep 2023 13:22:13 -0600 Subject: [PATCH 10/17] format fix for lint --- FFMpegCore/Helpers/FFMpegDownloader.cs | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore/Helpers/FFMpegDownloader.cs index f465f1b1..99e04c70 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore/Helpers/FFMpegDownloader.cs @@ -85,7 +85,7 @@ public static async Task> DownloadFFMpegSuite( return successList; } - + /// /// Download file from uri /// @@ -134,29 +134,21 @@ private class DownloadInfo private class BinaryInfo { - [JsonPropertyName("windows-64")] - public DownloadInfo? Windows64 { get; set; } + [JsonPropertyName("windows-64")] public DownloadInfo? Windows64 { get; set; } - [JsonPropertyName("windows-32")] - public DownloadInfo? Windows32 { get; set; } + [JsonPropertyName("windows-32")] public DownloadInfo? Windows32 { get; set; } - [JsonPropertyName("linux-32")] - public DownloadInfo? Linux32 { get; set; } + [JsonPropertyName("linux-32")] public DownloadInfo? Linux32 { get; set; } - [JsonPropertyName("linux-64")] - public DownloadInfo? Linux64 { get; set; } + [JsonPropertyName("linux-64")] public DownloadInfo? Linux64 { get; set; } - [JsonPropertyName("linux-armhf")] - public DownloadInfo? LinuxArmhf { get; set; } + [JsonPropertyName("linux-armhf")] public DownloadInfo? LinuxArmhf { get; set; } - [JsonPropertyName("linux-armel")] - public DownloadInfo? LinuxArmel { get; set; } + [JsonPropertyName("linux-armel")] public DownloadInfo? LinuxArmel { get; set; } - [JsonPropertyName("linux-arm64")] - public DownloadInfo? LinuxArm64 { get; set; } + [JsonPropertyName("linux-arm64")] public DownloadInfo? LinuxArm64 { get; set; } - [JsonPropertyName("osx-64")] - public DownloadInfo? Osx64 { get; set; } + [JsonPropertyName("osx-64")] public DownloadInfo? Osx64 { get; set; } /// /// Automatically get the compatible download info for current os and architecture From dfc486db1d8b0a796dcda1319676e1fb98062753 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Wed, 6 Sep 2023 13:42:22 -0600 Subject: [PATCH 11/17] ffmpeg downloader moved to seperate package --- .../FFMpegCore.Downloader.csproj | 23 ++ FFMpegCore.Downloader/FFMpegDownloader.cs | 272 ++++++++++++++++++ FFMpegCore.Test/FFMpegCore.Test.csproj | 1 + FFMpegCore.sln | 10 +- 4 files changed, 304 insertions(+), 2 deletions(-) create mode 100644 FFMpegCore.Downloader/FFMpegCore.Downloader.csproj create mode 100644 FFMpegCore.Downloader/FFMpegDownloader.cs diff --git a/FFMpegCore.Downloader/FFMpegCore.Downloader.csproj b/FFMpegCore.Downloader/FFMpegCore.Downloader.csproj new file mode 100644 index 00000000..720cbf1b --- /dev/null +++ b/FFMpegCore.Downloader/FFMpegCore.Downloader.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.1 + enable + + + + true + FFMpeg downloader extension for FFMpegCore + 5.0.0 + ../nupkg + + + ffmpeg ffprobe convert video audio mediafile resize analyze download + Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev, Kerry Cao + + + + + + + diff --git a/FFMpegCore.Downloader/FFMpegDownloader.cs b/FFMpegCore.Downloader/FFMpegDownloader.cs new file mode 100644 index 00000000..36f27c55 --- /dev/null +++ b/FFMpegCore.Downloader/FFMpegDownloader.cs @@ -0,0 +1,272 @@ +using System.IO.Compression; +using System.Net; +using System.Runtime.InteropServices; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace FFMpegCore.Downloader; + +/// +/// Downloads the latest FFMpeg suite binaries from ffbinaries.com. +/// +public class FFMpegDownloader +{ + [Flags] + public enum FFMpegBinaries : ushort + { + FFMpeg, + FFProbe, + FFPlay + } + + public enum FFMpegVersions : ushort + { + Latest, + V4_4_1, + V4_2_1, + V4_2, + V4_1, + V4_0, + V3_4, + V3_3, + V3_2 + } + + public enum PlatformOverride : short + { + Windows64, + Windows32, + Linux64, + Linux32, + LinuxArmhf, + LinuxArmel, + LinuxArm64, + Osx64 + } + + /// + /// Download the latest FFMpeg suite binaries for current platform + /// + /// used to explicitly state the version of binary you want to download + /// used to explicitly state the binaries you want to download (ffmpeg, ffprobe, ffplay) + /// used to explicitly state the os and architecture you want to download + /// a list of the binaries that have been successfully downloaded + public static async Task> DownloadFFMpegSuite( + FFMpegVersions version = FFMpegVersions.Latest, + FFMpegBinaries binaries = FFMpegBinaries.FFMpeg | FFMpegBinaries.FFProbe, + PlatformOverride? platformOverride = null) + { + var versionInfo = await GetVersionInfo(version); + var downloadInfo = versionInfo.BinaryInfo?.GetCompatibleDownloadInfo(platformOverride) ?? + throw new FFMpegDownloaderException("Failed to get compatible download info"); + + var successList = new List(); + + // if ffmpeg is selected + if (binaries.HasFlag(FFMpegBinaries.FFMpeg) && downloadInfo.FFMpeg is not null) + { + var zipStream = DownloadFileAsSteam(new Uri(downloadInfo.FFMpeg)); + successList.AddRange(ExtractZipAndSave(zipStream)); + } + + // if ffprobe is selected + if (binaries.HasFlag(FFMpegBinaries.FFProbe) && downloadInfo.FFProbe is not null) + { + var zipStream = DownloadFileAsSteam(new Uri(downloadInfo.FFProbe)); + successList.AddRange(ExtractZipAndSave(zipStream)); + } + + // if ffplay is selected + if (binaries.HasFlag(FFMpegBinaries.FFPlay) && downloadInfo.FFPlay is not null) + { + var zipStream = DownloadFileAsSteam(new Uri(downloadInfo.FFPlay)); + successList.AddRange(ExtractZipAndSave(zipStream)); + } + + return successList; + } + + /// + /// Download file from uri + /// + /// uri of the file + /// + private static MemoryStream DownloadFileAsSteam(Uri address) + { + var client = new WebClient(); + var fileStream = new MemoryStream(client.DownloadData(address)); + fileStream.Position = 0; + + return fileStream; + } + + /// + /// Extracts the binaries from the zip stream and saves them to the current binary folder + /// + /// steam of the zip file + /// + private static IEnumerable ExtractZipAndSave(Stream zipStream) + { + using var archive = new ZipArchive(zipStream, ZipArchiveMode.Read); + List files = new(); + foreach (var entry in archive.Entries) + { + if (entry.Name is "ffmpeg" or "ffmpeg.exe" or "ffprobe.exe" or "ffprobe" or "ffplay.exe" or "ffplay") + { + entry.ExtractToFile(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name), true); + files.Add(Path.Combine(GlobalFFOptions.Current.BinaryFolder, entry.Name)); + } + } + + return files; + } + + #region FFbinaries api + + private class DownloadInfo + { + [JsonPropertyName("ffmpeg")] public string? FFMpeg { get; set; } + + [JsonPropertyName("ffprobe")] public string? FFProbe { get; set; } + + [JsonPropertyName("ffplay")] public string? FFPlay { get; set; } + } + + private class BinaryInfo + { + [JsonPropertyName("windows-64")] public DownloadInfo? Windows64 { get; set; } + + [JsonPropertyName("windows-32")] public DownloadInfo? Windows32 { get; set; } + + [JsonPropertyName("linux-32")] public DownloadInfo? Linux32 { get; set; } + + [JsonPropertyName("linux-64")] public DownloadInfo? Linux64 { get; set; } + + [JsonPropertyName("linux-armhf")] public DownloadInfo? LinuxArmhf { get; set; } + + [JsonPropertyName("linux-armel")] public DownloadInfo? LinuxArmel { get; set; } + + [JsonPropertyName("linux-arm64")] public DownloadInfo? LinuxArm64 { get; set; } + + [JsonPropertyName("osx-64")] public DownloadInfo? Osx64 { get; set; } + + /// + /// Automatically get the compatible download info for current os and architecture + /// + /// + /// + /// + /// + public DownloadInfo? GetCompatibleDownloadInfo(PlatformOverride? platformOverride = null) + { + if (platformOverride is not null) + { + return platformOverride switch + { + PlatformOverride.Windows64 => Windows64, + PlatformOverride.Windows32 => Windows32, + PlatformOverride.Linux64 => Linux64, + PlatformOverride.Linux32 => Linux32, + PlatformOverride.LinuxArmhf => LinuxArmhf, + PlatformOverride.LinuxArmel => LinuxArmel, + PlatformOverride.LinuxArm64 => LinuxArm64, + PlatformOverride.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)) + { + return Osx64; + } + + throw new PlatformNotSupportedException("Unsupported OS or Architecture"); + } + } + + private class VersionInfo + { + [JsonPropertyName("version")] public string? Version { get; set; } + + [JsonPropertyName("permalink")] public string? Permalink { get; set; } + + [JsonPropertyName("bin")] public BinaryInfo? BinaryInfo { get; set; } + } + + private static readonly Dictionary _FFBinariesAPIs = new() + { + { FFMpegVersions.Latest, "https://ffbinaries.com/api/v1/version/latest" }, + { FFMpegVersions.V4_4_1, "https://ffbinaries.com/api/v1/version/4.4.1" }, + { FFMpegVersions.V4_2_1, "https://ffbinaries.com/api/v1/version/4.2.1" }, + { FFMpegVersions.V4_2, "https://ffbinaries.com/api/v1/version/4.2" }, + { FFMpegVersions.V4_1, "https://ffbinaries.com/api/v1/version/4.1" }, + { FFMpegVersions.V4_0, "https://ffbinaries.com/api/v1/version/4.0" }, + { FFMpegVersions.V3_4, "https://ffbinaries.com/api/v1/version/3.4" }, + { FFMpegVersions.V3_3, "https://ffbinaries.com/api/v1/version/3.3" }, + { FFMpegVersions.V3_2, "https://ffbinaries.com/api/v1/version/3.2" } + }; + + /// + /// Get version info from ffbinaries.com + /// + /// use to explicitly state the version of ffmpeg you want + /// + /// + private static async Task GetVersionInfo(FFMpegVersions version) + { + if (!_FFBinariesAPIs.TryGetValue(version, out var versionUri)) + { + throw new FFMpegDownloaderException($"Invalid version selected: {version}", "contact dev"); + } + + HttpClient client = new(); + 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(jsonString); + + return versionInfo ?? + throw new FFMpegDownloaderException($"Failed to deserialize version info from {versionUri}", jsonString); + } + + #endregion +} + +/// +/// Custom exception for FFMpegDownloader +/// +public class FFMpegDownloaderException : Exception +{ + public FFMpegDownloaderException(string message) : base(message) + { + } + + public FFMpegDownloaderException(string message, string detail) : base(message) + { + Detail = detail; + } + + public string Detail { get; set; } = ""; +} diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj index b78af1b7..d54d2692 100644 --- a/FFMpegCore.Test/FFMpegCore.Test.csproj +++ b/FFMpegCore.Test/FFMpegCore.Test.csproj @@ -24,6 +24,7 @@ + diff --git a/FFMpegCore.sln b/FFMpegCore.sln index 7ab09297..f7f42d26 100644 --- a/FFMpegCore.sln +++ b/FFMpegCore.sln @@ -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.Downloader", "FFMpegCore.Downloader\FFMpegCore.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 From d978d7d9b4d42862a18a74d9358220c13fc7ba49 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Wed, 6 Sep 2023 13:42:22 -0600 Subject: [PATCH 12/17] ffmpeg downloader moved to separate package --- .../FFMpegCore.Downloader.csproj | 23 +++++++++++++++++++ .../FFMpegDownloader.cs | 2 +- FFMpegCore.Test/DownloaderTests.cs | 2 +- FFMpegCore.Test/FFMpegCore.Test.csproj | 1 + FFMpegCore.sln | 10 ++++++-- 5 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 FFMpegCore.Downloader/FFMpegCore.Downloader.csproj rename {FFMpegCore/Helpers => FFMpegCore.Downloader}/FFMpegDownloader.cs (99%) diff --git a/FFMpegCore.Downloader/FFMpegCore.Downloader.csproj b/FFMpegCore.Downloader/FFMpegCore.Downloader.csproj new file mode 100644 index 00000000..720cbf1b --- /dev/null +++ b/FFMpegCore.Downloader/FFMpegCore.Downloader.csproj @@ -0,0 +1,23 @@ + + + + netstandard2.1 + enable + + + + true + FFMpeg downloader extension for FFMpegCore + 5.0.0 + ../nupkg + + + ffmpeg ffprobe convert video audio mediafile resize analyze download + Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev, Kerry Cao + + + + + + + diff --git a/FFMpegCore/Helpers/FFMpegDownloader.cs b/FFMpegCore.Downloader/FFMpegDownloader.cs similarity index 99% rename from FFMpegCore/Helpers/FFMpegDownloader.cs rename to FFMpegCore.Downloader/FFMpegDownloader.cs index 99e04c70..36f27c55 100644 --- a/FFMpegCore/Helpers/FFMpegDownloader.cs +++ b/FFMpegCore.Downloader/FFMpegDownloader.cs @@ -4,7 +4,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace FFMpegCore.Helpers; +namespace FFMpegCore.Downloader; /// /// Downloads the latest FFMpeg suite binaries from ffbinaries.com. diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index c677d5da..e394dc03 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -1,4 +1,4 @@ -using FFMpegCore.Helpers; +using FFMpegCore.Downloader; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace FFMpegCore.Test; diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj index b78af1b7..d54d2692 100644 --- a/FFMpegCore.Test/FFMpegCore.Test.csproj +++ b/FFMpegCore.Test/FFMpegCore.Test.csproj @@ -24,6 +24,7 @@ + diff --git a/FFMpegCore.sln b/FFMpegCore.sln index 7ab09297..f7f42d26 100644 --- a/FFMpegCore.sln +++ b/FFMpegCore.sln @@ -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.Downloader", "FFMpegCore.Downloader\FFMpegCore.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 From ae5ae973fae456ef4071c3da91c7fbf61a919b32 Mon Sep 17 00:00:00 2001 From: Kerry Cao Date: Wed, 6 Sep 2023 14:07:08 -0600 Subject: [PATCH 13/17] FFMpegCore.Downloader renamed to FFMpegCore.Extensions.Downloader --- .../FFMpegCore.Extensions.Downloader.csproj | 0 .../FFMpegDownloader.cs | 2 +- FFMpegCore.Test/DownloaderTests.cs | 2 +- FFMpegCore.Test/FFMpegCore.Test.csproj | 2 +- FFMpegCore.sln | 2 +- 5 files changed, 4 insertions(+), 4 deletions(-) rename FFMpegCore.Downloader/FFMpegCore.Downloader.csproj => FFMpegCore.Extensions.Downloader/FFMpegCore.Extensions.Downloader.csproj (100%) rename {FFMpegCore.Downloader => FFMpegCore.Extensions.Downloader}/FFMpegDownloader.cs (99%) diff --git a/FFMpegCore.Downloader/FFMpegCore.Downloader.csproj b/FFMpegCore.Extensions.Downloader/FFMpegCore.Extensions.Downloader.csproj similarity index 100% rename from FFMpegCore.Downloader/FFMpegCore.Downloader.csproj rename to FFMpegCore.Extensions.Downloader/FFMpegCore.Extensions.Downloader.csproj diff --git a/FFMpegCore.Downloader/FFMpegDownloader.cs b/FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs similarity index 99% rename from FFMpegCore.Downloader/FFMpegDownloader.cs rename to FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs index 36f27c55..097c9f6b 100644 --- a/FFMpegCore.Downloader/FFMpegDownloader.cs +++ b/FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs @@ -4,7 +4,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -namespace FFMpegCore.Downloader; +namespace FFMpegCore.Extensions.Downloader; /// /// Downloads the latest FFMpeg suite binaries from ffbinaries.com. diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index e394dc03..3d65a3d7 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -1,4 +1,4 @@ -using FFMpegCore.Downloader; +using FFMpegCore.Extensions.Downloader; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace FFMpegCore.Test; diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj index d54d2692..220f05c7 100644 --- a/FFMpegCore.Test/FFMpegCore.Test.csproj +++ b/FFMpegCore.Test/FFMpegCore.Test.csproj @@ -24,7 +24,7 @@ - + diff --git a/FFMpegCore.sln b/FFMpegCore.sln index f7f42d26..b99a44ea 100644 --- a/FFMpegCore.sln +++ b/FFMpegCore.sln @@ -13,7 +13,7 @@ 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.Downloader", "FFMpegCore.Downloader\FFMpegCore.Downloader.csproj", "{5FA30158-CAB0-44FD-AD98-C31F5E3D5A56}" +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 From 5bedbdb1076e0a954d4f3a895491bdde85c1cb85 Mon Sep 17 00:00:00 2001 From: K <28016308+yuqian5@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:45:14 -0600 Subject: [PATCH 14/17] Update README.md --- README.md | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index b2df37ae..716d85fa 100644 --- a/README.md +++ b/README.md @@ -165,14 +165,7 @@ If you want to use `System.Drawing.Bitmap`s as `IVideoFrame`s, a `BitmapVideoFra ## Runtime Auto Installation You can install a version of ffmpeg suite at runtime using `FFMpegDownloader.DownloadFFMpegSuite();` -Or you can download only the desired binary using `FFMpegDownloader.DownloadFFMpeg()`, `FFMpegDownloader.DownloadFFProbe()`, `FFMpegDownloader.DownloadFFPlay()`. - -| OS | Support | -|---------|:-------------------------------------------------:| -| Windows | x64 Fully Supported, x86 Up to version V4.2.1 | -| Mac OSX | NOT YET | -| Linux | NOT YET | - +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/). From 22fa0023947149dc0fe11b951783e9a5d7f645d8 Mon Sep 17 00:00:00 2001 From: K <28016308+yuqian5@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:50:59 -0600 Subject: [PATCH 15/17] Debug for CI failure --- FFMpegCore.Test/DownloaderTests.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index 3d65a3d7..8fcdc4a6 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -6,6 +6,7 @@ namespace FFMpegCore.Test; [TestClass] public class DownloaderTests { + [Ignore] [TestMethod] public void GetAllLatestSuiteTest() { @@ -15,6 +16,7 @@ public void GetAllLatestSuiteTest() Assert.IsTrue(binaries.Count >= 2); // many platforms have only ffmpeg and ffprobe } + [Ignore] [TestMethod] public void GetSpecificVersionTest() { From 6524b1cd4d90f1d204c359823045f20300d546ab Mon Sep 17 00:00:00 2001 From: K <28016308+yuqian5@users.noreply.github.com> Date: Tue, 10 Oct 2023 15:59:11 -0600 Subject: [PATCH 16/17] Update DownloaderTests.cs --- FFMpegCore.Test/DownloaderTests.cs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/FFMpegCore.Test/DownloaderTests.cs b/FFMpegCore.Test/DownloaderTests.cs index 8fcdc4a6..5a89a59c 100644 --- a/FFMpegCore.Test/DownloaderTests.cs +++ b/FFMpegCore.Test/DownloaderTests.cs @@ -6,21 +6,17 @@ namespace FFMpegCore.Test; [TestClass] public class DownloaderTests { - [Ignore] [TestMethod] public void GetAllLatestSuiteTest() { - var binaries = FFMpegDownloader.DownloadFFMpegSuite(binaries: FFMpegDownloader.FFMpegBinaries.FFProbe | - FFMpegDownloader.FFMpegBinaries.FFMpeg | - FFMpegDownloader.FFMpegBinaries.FFPlay).Result; - Assert.IsTrue(binaries.Count >= 2); // many platforms have only ffmpeg and ffprobe + var binaries = FFMpegDownloader.DownloadFFMpegSuite(binaries: FFMpegDownloader.FFMpegBinaries.FFMpeg).Result; + Assert.IsTrue(binaries.Count == 1); // many platforms have only ffmpeg and ffprobe } - [Ignore] [TestMethod] public void GetSpecificVersionTest() { - var binaries = FFMpegDownloader.DownloadFFMpegSuite(FFMpegDownloader.FFMpegVersions.V4_0).Result; - Assert.IsTrue(binaries.Count == 2); + var binaries = FFMpegDownloader.DownloadFFMpegSuite(FFMpegDownloader.FFMpegVersions.V4_0, binaries: FFMpegDownloader.FFMpegBinaries.FFMpeg).Result; + Assert.IsTrue(binaries.Count == 1); } } From 09ae9447c854a82c51152aafc8ae00c42de4a907 Mon Sep 17 00:00:00 2001 From: K <28016308+yuqian5@users.noreply.github.com> Date: Thu, 4 Jan 2024 16:59:25 -0700 Subject: [PATCH 17/17] version 5.1 and 6.1 added --- FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs b/FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs index 097c9f6b..139921c5 100644 --- a/FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs +++ b/FFMpegCore.Extensions.Downloader/FFMpegDownloader.cs @@ -22,6 +22,8 @@ public enum FFMpegBinaries : ushort public enum FFMpegVersions : ushort { Latest, + V6_1, + V5_1, V4_4_1, V4_2_1, V4_2, @@ -213,6 +215,8 @@ private class VersionInfo private static readonly Dictionary _FFBinariesAPIs = new() { { FFMpegVersions.Latest, "https://ffbinaries.com/api/v1/version/latest" }, + { FFMpegVersions.V6_1, "https://ffbinaries.com/api/v1/version/6.1" }, + { FFMpegVersions.V5_1, "https://ffbinaries.com/api/v1/version/5.1" }, { FFMpegVersions.V4_4_1, "https://ffbinaries.com/api/v1/version/4.4.1" }, { FFMpegVersions.V4_2_1, "https://ffbinaries.com/api/v1/version/4.2.1" }, { FFMpegVersions.V4_2, "https://ffbinaries.com/api/v1/version/4.2" },