lampac/Shared/Engine/FFmpeg.cs

179 lines
6.8 KiB
C#

using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Shared.Engine
{
/// <summary>
/// https://github.com/BtbN/FFmpeg-Builds/releases
/// </summary>
public static class FFmpeg
{
private const string baseDownloadUrl = "https://github.com/lampac-talks/lampac/releases/download/ffmpeg";
#region InitializationAsync
static bool disableInstall = false;
async public static Task<bool> InitializationAsync()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
#region Windows
if (File.Exists("data/ffmpeg.exe") && File.Exists("data/ffprobe.exe"))
{
Console.WriteLine("FFmpeg: Initialization");
return true;
}
if (RuntimeInformation.ProcessArchitecture != Architecture.X64 && RuntimeInformation.ProcessArchitecture != Architecture.Arm64)
{
Console.WriteLine("FFmpeg: Architecture unknown");
return false;
}
if (disableInstall)
return true;
disableInstall = true;
string arh = RuntimeInformation.ProcessArchitecture == Architecture.X64 ? "64" : "arm64";
foreach (string fileName in new string[] { "ffmpeg", "ffprobe" })
{
if (File.Exists($"data/{fileName}.exe"))
continue;
if (!await Http.DownloadFile($"{baseDownloadUrl}/{fileName}-win{arh}-gpl.exe", $"data/{fileName}.exe"))
File.Delete($"data/{fileName}.exe");
}
bool success = File.Exists("data/ffmpeg.exe") && File.Exists("data/ffprobe.exe");
Console.WriteLine(success ? "FFmpeg: Initialization" : "FFmpeg: error download");
disableInstall = false;
return success;
#endregion
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
#region Linux
if ((File.Exists("data/ffmpeg") && File.Exists("data/ffprobe")) || File.Exists("/bin/ffmpeg"))
{
Console.WriteLine("FFmpeg: Initialization");
return true;
}
string version = await Bash.Run("ffmpeg -version");
if (version == null || !version.Contains("FFmpeg developers"))
{
if (disableInstall)
return true;
disableInstall = true;
if (RuntimeInformation.ProcessArchitecture == Architecture.X64 || RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
string arh = RuntimeInformation.ProcessArchitecture == Architecture.X64 ? "64" : "arm64";
foreach (string fileName in new string[] { "ffmpeg", "ffprobe" })
{
if (File.Exists($"data/{fileName}"))
continue;
if (!await Http.DownloadFile($"{baseDownloadUrl}/{fileName}-linux{arh}-gpl", $"data/{fileName}"))
{
File.Delete($"data/{fileName}");
continue;
}
Bash.Invoke($"chmod +x {Path.Join(Directory.GetCurrentDirectory(), $"data/{fileName}")}");
}
bool success = File.Exists("data/ffmpeg") && File.Exists("data/ffprobe");
await Task.Delay(1000); // Wait for chmod to complete
Console.WriteLine(success ? "FFmpeg: Initialization" : "FFmpeg: error download");
disableInstall = false;
return success;
}
else
{
await Bash.Run("apt update && apt install -y ffmpeg");
version = await Bash.Run("ffmpeg -version");
if (version == null || !version.Contains("FFmpeg developers"))
{
Console.WriteLine("FFmpeg: error install ffmpeg");
disableInstall = false;
return false;
}
}
}
Console.WriteLine("FFmpeg: Initialization");
return true;
#endregion
}
Console.WriteLine("FFmpeg: OS unknown");
return false;
}
#endregion
#region RunAsync
async public static ValueTask<(string outputData, string errorData)> RunAsync(string comand, string workingDirectory = null, ProcessPriorityClass? priorityClass = null)
{
try
{
var process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.FileName = AppInit.Win32NT ? "data/ffmpeg.exe" : File.Exists("data/ffmpeg") ? "data/ffmpeg" : "ffmpeg";
process.StartInfo.Arguments = comand;
process.StartInfo.WorkingDirectory = workingDirectory;
process.Start();
if (priorityClass != null)
{
try
{
process.PriorityClass = (ProcessPriorityClass)priorityClass;
}
catch (InvalidOperationException)
{
// Процесс завершился до установки приоритета
}
catch(Exception ex)
{
Console.WriteLine("FFmpeg: " + ex.Message);
}
}
string outputData = string.Empty, errorData = string.Empty;
process.OutputDataReceived += (sender, args) =>
{
if (!string.IsNullOrEmpty(args.Data))
outputData += args.Data + "\n";
};
process.ErrorDataReceived += (sender, args) =>
{
if (!string.IsNullOrEmpty(args.Data))
errorData += args.Data + "\n";
};
process.BeginOutputReadLine();
process.BeginErrorReadLine();
await process.WaitForExitAsync();
return (outputData, errorData);
}
catch
{
return default;
}
}
#endregion
}
}