mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-14 02:04:14 +01:00
Cleanup
This commit is contained in:
parent
7444899106
commit
df0205fb11
18 changed files with 203 additions and 190 deletions
|
@ -10,39 +10,39 @@ public class FFMpegOptionsTest
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Options_Initialized()
|
public void Options_Initialized()
|
||||||
{
|
{
|
||||||
Assert.IsNotNull(FFMpegOptions.Options);
|
Assert.IsNotNull(GlobalFFOptions.Current);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Options_Defaults_Configured()
|
public void Options_Defaults_Configured()
|
||||||
{
|
{
|
||||||
Assert.AreEqual(new FFMpegOptions().RootDirectory, $"");
|
Assert.AreEqual(new FFOptions().BinaryFolder, $"");
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Options_Loaded_From_File()
|
public void Options_Loaded_From_File()
|
||||||
{
|
{
|
||||||
Assert.AreEqual(
|
Assert.AreEqual(
|
||||||
FFMpegOptions.Options.RootDirectory,
|
GlobalFFOptions.Current.BinaryFolder,
|
||||||
JsonConvert.DeserializeObject<FFMpegOptions>(File.ReadAllText("ffmpeg.config.json")).RootDirectory
|
JsonConvert.DeserializeObject<FFOptions>(File.ReadAllText("ffmpeg.config.json")).BinaryFolder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Options_Set_Programmatically()
|
public void Options_Set_Programmatically()
|
||||||
{
|
{
|
||||||
var original = FFMpegOptions.Options;
|
var original = GlobalFFOptions.Current;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
FFMpegOptions.Configure(new FFMpegOptions { RootDirectory = "Whatever" });
|
GlobalFFOptions.Configure(new FFOptions { BinaryFolder = "Whatever" });
|
||||||
Assert.AreEqual(
|
Assert.AreEqual(
|
||||||
FFMpegOptions.Options.RootDirectory,
|
GlobalFFOptions.Current.BinaryFolder,
|
||||||
"Whatever"
|
"Whatever"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
FFMpegOptions.Configure(original);
|
GlobalFFOptions.Configure(original);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ public void Video_ToMP4_Args_StreamPipe()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure()
|
public async Task Video_ToMP4_Args_StreamOutputPipe_Async_Failure()
|
||||||
{
|
{
|
||||||
await Assert.ThrowsExceptionAsync<FFMpegProcessException>(async () =>
|
await Assert.ThrowsExceptionAsync<FFMpegException>(async () =>
|
||||||
{
|
{
|
||||||
await using var ms = new MemoryStream();
|
await using var ms = new MemoryStream();
|
||||||
var pipeSource = new StreamPipeSink(ms);
|
var pipeSource = new StreamPipeSink(ms);
|
||||||
|
@ -134,7 +134,7 @@ public void Video_StreamFile_OutputToMemoryStream()
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public void Video_ToMP4_Args_StreamOutputPipe_Failure()
|
public void Video_ToMP4_Args_StreamOutputPipe_Failure()
|
||||||
{
|
{
|
||||||
Assert.ThrowsException<FFMpegProcessException>(() =>
|
Assert.ThrowsException<FFMpegException>(() =>
|
||||||
{
|
{
|
||||||
using var ms = new MemoryStream();
|
using var ms = new MemoryStream();
|
||||||
FFMpegArguments
|
FFMpegArguments
|
||||||
|
@ -435,7 +435,7 @@ public void Video_OutputsData()
|
||||||
var outputFile = new TemporaryFile("out.mp4");
|
var outputFile = new TemporaryFile("out.mp4");
|
||||||
var dataReceived = false;
|
var dataReceived = false;
|
||||||
|
|
||||||
FFMpegOptions.Configure(opt => opt.Encoding = Encoding.UTF8);
|
GlobalFFOptions.Configure(opt => opt.Encoding = Encoding.UTF8);
|
||||||
var success = FFMpegArguments
|
var success = FFMpegArguments
|
||||||
.FromFileInput(TestResources.Mp4Video)
|
.FromFileInput(TestResources.Mp4Video)
|
||||||
.WithGlobalOptions(options => options
|
.WithGlobalOptions(options => options
|
||||||
|
|
|
@ -18,7 +18,7 @@ public DemuxConcatArgument(IEnumerable<string> values)
|
||||||
{
|
{
|
||||||
Values = values.Select(value => $"file '{value}'");
|
Values = values.Select(value => $"file '{value}'");
|
||||||
}
|
}
|
||||||
private readonly string _tempFileName = Path.Combine(FFMpegOptions.Options.TempDirectory, Guid.NewGuid() + ".txt");
|
private readonly string _tempFileName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"concat_{Guid.NewGuid()}.txt");
|
||||||
|
|
||||||
public void Pre() => File.WriteAllLines(_tempFileName, Values);
|
public void Pre() => File.WriteAllLines(_tempFileName, Values);
|
||||||
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
public Task During(CancellationToken cancellationToken = default) => Task.CompletedTask;
|
||||||
|
|
|
@ -15,8 +15,8 @@ public string Extension
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (FFMpegOptions.Options.ExtensionOverrides.ContainsKey(Name))
|
if (GlobalFFOptions.Current.ExtensionOverrides.ContainsKey(Name))
|
||||||
return FFMpegOptions.Options.ExtensionOverrides[Name];
|
return GlobalFFOptions.Current.ExtensionOverrides[Name];
|
||||||
return "." + Name;
|
return "." + Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,53 +4,43 @@ namespace FFMpegCore.Exceptions
|
||||||
{
|
{
|
||||||
public enum FFMpegExceptionType
|
public enum FFMpegExceptionType
|
||||||
{
|
{
|
||||||
Dependency,
|
|
||||||
Conversion,
|
Conversion,
|
||||||
File,
|
File,
|
||||||
Operation,
|
Operation,
|
||||||
Process
|
Process
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class FFException : Exception
|
|
||||||
{
|
|
||||||
protected FFException(string message) : base(message) { }
|
|
||||||
protected FFException(string message, Exception innerException) : base(message, innerException) { }
|
|
||||||
}
|
|
||||||
public abstract class FFProcessException : FFException
|
|
||||||
{
|
|
||||||
protected FFProcessException(string process, int exitCode, string errorOutput)
|
|
||||||
: base($"{process} exited with non-zero exit-code {exitCode}\n{errorOutput}")
|
|
||||||
{
|
|
||||||
ExitCode = exitCode;
|
|
||||||
ErrorOutput = errorOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ExitCode { get; }
|
|
||||||
public string ErrorOutput { get; }
|
|
||||||
}
|
|
||||||
public class FFMpegProcessException : FFProcessException
|
|
||||||
{
|
|
||||||
public FFMpegProcessException(int exitCode, string errorOutput)
|
|
||||||
: base("ffmpeg", exitCode, errorOutput) { }
|
|
||||||
}
|
|
||||||
public class FFProbeProcessException : FFProcessException
|
|
||||||
{
|
|
||||||
public FFProbeProcessException(int exitCode, string errorOutput)
|
|
||||||
: base("ffprobe", exitCode, errorOutput) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class FFMpegException : Exception
|
public class FFMpegException : Exception
|
||||||
{
|
{
|
||||||
public FFMpegException(FFMpegExceptionType type, string? message = null, Exception? innerException = null, string ffMpegErrorOutput = "")
|
public FFMpegException(FFMpegExceptionType type, string message, Exception? innerException = null, string ffMpegErrorOutput = "")
|
||||||
: base(message, innerException)
|
: base(message, innerException)
|
||||||
{
|
{
|
||||||
FFMpegErrorOutput = ffMpegErrorOutput;
|
FFMpegErrorOutput = ffMpegErrorOutput;
|
||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
public FFMpegException(FFMpegExceptionType type, string message, string ffMpegErrorOutput = "")
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
FFMpegErrorOutput = ffMpegErrorOutput;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
public FFMpegException(FFMpegExceptionType type, string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
FFMpegErrorOutput = string.Empty;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
public FFMpegExceptionType Type { get; }
|
public FFMpegExceptionType Type { get; }
|
||||||
public string FFMpegErrorOutput { get; }
|
public string FFMpegErrorOutput { get; }
|
||||||
}
|
}
|
||||||
|
public class FFOptionsException : Exception
|
||||||
|
{
|
||||||
|
public FFOptionsException(string message, Exception? innerException = null)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class FFMpegArgumentException : Exception
|
public class FFMpegArgumentException : Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -254,8 +254,8 @@ public static bool Join(string output, params string[] videos)
|
||||||
{
|
{
|
||||||
var video = FFProbe.Analyse(videoPath);
|
var video = FFProbe.Analyse(videoPath);
|
||||||
FFMpegHelper.ConversionSizeExceptionCheck(video);
|
FFMpegHelper.ConversionSizeExceptionCheck(video);
|
||||||
var destinationPath = Path.Combine(FFMpegOptions.Options.TempDirectory, $"{Path.GetFileNameWithoutExtension(videoPath)}{FileExtension.Ts}");
|
var destinationPath = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, $"{Path.GetFileNameWithoutExtension(videoPath)}{FileExtension.Ts}");
|
||||||
Directory.CreateDirectory(FFMpegOptions.Options.TempDirectory);
|
Directory.CreateDirectory(GlobalFFOptions.Current.TemporaryFilesFolder);
|
||||||
Convert(videoPath, destinationPath, VideoType.Ts);
|
Convert(videoPath, destinationPath, VideoType.Ts);
|
||||||
return destinationPath;
|
return destinationPath;
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
@ -284,7 +284,7 @@ public static bool Join(string output, params string[] videos)
|
||||||
/// <returns>Output video information.</returns>
|
/// <returns>Output video information.</returns>
|
||||||
public static bool JoinImageSequence(string output, double frameRate = 30, params ImageInfo[] images)
|
public static bool JoinImageSequence(string output, double frameRate = 30, params ImageInfo[] images)
|
||||||
{
|
{
|
||||||
var tempFolderName = Path.Combine(FFMpegOptions.Options.TempDirectory, Guid.NewGuid().ToString());
|
var tempFolderName = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString());
|
||||||
var temporaryImageFiles = images.Select((image, index) =>
|
var temporaryImageFiles = images.Select((image, index) =>
|
||||||
{
|
{
|
||||||
FFMpegHelper.ConversionSizeExceptionCheck(Image.FromFile(image.FullName));
|
FFMpegHelper.ConversionSizeExceptionCheck(Image.FromFile(image.FullName));
|
||||||
|
@ -398,7 +398,7 @@ internal static IReadOnlyList<PixelFormat> GetPixelFormatsInternal()
|
||||||
FFMpegHelper.RootExceptionCheck();
|
FFMpegHelper.RootExceptionCheck();
|
||||||
|
|
||||||
var list = new List<PixelFormat>();
|
var list = new List<PixelFormat>();
|
||||||
using var instance = new Instances.Instance(FFMpegOptions.Options.FFMpegBinary(), "-pix_fmts");
|
using var instance = new Instances.Instance(GlobalFFOptions.GetFFMpegBinaryPath(), "-pix_fmts");
|
||||||
instance.DataReceived += (e, args) =>
|
instance.DataReceived += (e, args) =>
|
||||||
{
|
{
|
||||||
if (PixelFormat.TryParse(args.Data, out var format))
|
if (PixelFormat.TryParse(args.Data, out var format))
|
||||||
|
@ -413,14 +413,14 @@ internal static IReadOnlyList<PixelFormat> GetPixelFormatsInternal()
|
||||||
|
|
||||||
public static IReadOnlyList<PixelFormat> GetPixelFormats()
|
public static IReadOnlyList<PixelFormat> GetPixelFormats()
|
||||||
{
|
{
|
||||||
if (!FFMpegOptions.Options.UseCache)
|
if (!GlobalFFOptions.Current.UseCache)
|
||||||
return GetPixelFormatsInternal();
|
return GetPixelFormatsInternal();
|
||||||
return FFMpegCache.PixelFormats.Values.ToList().AsReadOnly();
|
return FFMpegCache.PixelFormats.Values.ToList().AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetPixelFormat(string name, out PixelFormat fmt)
|
public static bool TryGetPixelFormat(string name, out PixelFormat fmt)
|
||||||
{
|
{
|
||||||
if (!FFMpegOptions.Options.UseCache)
|
if (!GlobalFFOptions.Current.UseCache)
|
||||||
{
|
{
|
||||||
fmt = GetPixelFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
|
fmt = GetPixelFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
|
||||||
return fmt != null;
|
return fmt != null;
|
||||||
|
@ -443,7 +443,7 @@ private static void ParsePartOfCodecs(Dictionary<string, Codec> codecs, string a
|
||||||
{
|
{
|
||||||
FFMpegHelper.RootExceptionCheck();
|
FFMpegHelper.RootExceptionCheck();
|
||||||
|
|
||||||
using var instance = new Instances.Instance(FFMpegOptions.Options.FFMpegBinary(), arguments);
|
using var instance = new Instances.Instance(GlobalFFOptions.GetFFMpegBinaryPath(), arguments);
|
||||||
instance.DataReceived += (e, args) =>
|
instance.DataReceived += (e, args) =>
|
||||||
{
|
{
|
||||||
var codec = parser(args.Data);
|
var codec = parser(args.Data);
|
||||||
|
@ -485,14 +485,14 @@ internal static Dictionary<string, Codec> GetCodecsInternal()
|
||||||
|
|
||||||
public static IReadOnlyList<Codec> GetCodecs()
|
public static IReadOnlyList<Codec> GetCodecs()
|
||||||
{
|
{
|
||||||
if (!FFMpegOptions.Options.UseCache)
|
if (!GlobalFFOptions.Current.UseCache)
|
||||||
return GetCodecsInternal().Values.ToList().AsReadOnly();
|
return GetCodecsInternal().Values.ToList().AsReadOnly();
|
||||||
return FFMpegCache.Codecs.Values.ToList().AsReadOnly();
|
return FFMpegCache.Codecs.Values.ToList().AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IReadOnlyList<Codec> GetCodecs(CodecType type)
|
public static IReadOnlyList<Codec> GetCodecs(CodecType type)
|
||||||
{
|
{
|
||||||
if (!FFMpegOptions.Options.UseCache)
|
if (!GlobalFFOptions.Current.UseCache)
|
||||||
return GetCodecsInternal().Values.Where(x => x.Type == type).ToList().AsReadOnly();
|
return GetCodecsInternal().Values.Where(x => x.Type == type).ToList().AsReadOnly();
|
||||||
return FFMpegCache.Codecs.Values.Where(x=>x.Type == type).ToList().AsReadOnly();
|
return FFMpegCache.Codecs.Values.Where(x=>x.Type == type).ToList().AsReadOnly();
|
||||||
}
|
}
|
||||||
|
@ -504,7 +504,7 @@ public static IReadOnlyList<Codec> GetCodecs(CodecType type)
|
||||||
|
|
||||||
public static bool TryGetCodec(string name, out Codec codec)
|
public static bool TryGetCodec(string name, out Codec codec)
|
||||||
{
|
{
|
||||||
if (!FFMpegOptions.Options.UseCache)
|
if (!GlobalFFOptions.Current.UseCache)
|
||||||
{
|
{
|
||||||
codec = GetCodecsInternal().Values.FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
|
codec = GetCodecsInternal().Values.FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
|
||||||
return codec != null;
|
return codec != null;
|
||||||
|
@ -527,7 +527,7 @@ internal static IReadOnlyList<ContainerFormat> GetContainersFormatsInternal()
|
||||||
FFMpegHelper.RootExceptionCheck();
|
FFMpegHelper.RootExceptionCheck();
|
||||||
|
|
||||||
var list = new List<ContainerFormat>();
|
var list = new List<ContainerFormat>();
|
||||||
using var instance = new Instances.Instance(FFMpegOptions.Options.FFMpegBinary(), "-formats");
|
using var instance = new Instances.Instance(GlobalFFOptions.GetFFMpegBinaryPath(), "-formats");
|
||||||
instance.DataReceived += (e, args) =>
|
instance.DataReceived += (e, args) =>
|
||||||
{
|
{
|
||||||
if (ContainerFormat.TryParse(args.Data, out var fmt))
|
if (ContainerFormat.TryParse(args.Data, out var fmt))
|
||||||
|
@ -542,14 +542,14 @@ internal static IReadOnlyList<ContainerFormat> GetContainersFormatsInternal()
|
||||||
|
|
||||||
public static IReadOnlyList<ContainerFormat> GetContainerFormats()
|
public static IReadOnlyList<ContainerFormat> GetContainerFormats()
|
||||||
{
|
{
|
||||||
if (!FFMpegOptions.Options.UseCache)
|
if (!GlobalFFOptions.Current.UseCache)
|
||||||
return GetContainersFormatsInternal();
|
return GetContainersFormatsInternal();
|
||||||
return FFMpegCache.ContainerFormats.Values.ToList().AsReadOnly();
|
return FFMpegCache.ContainerFormats.Values.ToList().AsReadOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool TryGetContainerFormat(string name, out ContainerFormat fmt)
|
public static bool TryGetContainerFormat(string name, out ContainerFormat fmt)
|
||||||
{
|
{
|
||||||
if (!FFMpegOptions.Options.UseCache)
|
if (!GlobalFFOptions.Current.UseCache)
|
||||||
{
|
{
|
||||||
fmt = GetContainersFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
|
fmt = GetContainersFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim());
|
||||||
return fmt != null;
|
return fmt != null;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
namespace FFMpegCore
|
namespace FFMpegCore
|
||||||
{
|
{
|
||||||
public class FFMpegArgumentOptions : FFMpegOptionsBase
|
public class FFMpegArgumentOptions : FFMpegArgumentsBase
|
||||||
{
|
{
|
||||||
internal FFMpegArgumentOptions() { }
|
internal FFMpegArgumentOptions() { }
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ public FFMpegArgumentProcessor CancellableThrough(out Action cancel, int timeout
|
||||||
cancel = () => CancelEvent?.Invoke(this, timeout);
|
cancel = () => CancelEvent?.Invoke(this, timeout);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public bool ProcessSynchronously(bool throwOnError = true)
|
public bool ProcessSynchronously(bool throwOnError = true, FFOptions? ffMpegOptions = null)
|
||||||
{
|
{
|
||||||
using var instance = PrepareInstance(out var cancellationTokenSource);
|
using var instance = PrepareInstance(ffMpegOptions ?? GlobalFFOptions.Current, out var cancellationTokenSource);
|
||||||
var errorCode = -1;
|
var errorCode = -1;
|
||||||
|
|
||||||
void OnCancelEvent(object sender, int timeout)
|
void OnCancelEvent(object sender, int timeout)
|
||||||
|
@ -90,9 +90,9 @@ void OnCancelEvent(object sender, int timeout)
|
||||||
return HandleCompletion(throwOnError, errorCode, instance.ErrorData);
|
return HandleCompletion(throwOnError, errorCode, instance.ErrorData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ProcessAsynchronously(bool throwOnError = true)
|
public async Task<bool> ProcessAsynchronously(bool throwOnError = true, FFOptions? ffMpegOptions = null)
|
||||||
{
|
{
|
||||||
using var instance = PrepareInstance(out var cancellationTokenSource);
|
using var instance = PrepareInstance(ffMpegOptions ?? GlobalFFOptions.Current, out var cancellationTokenSource);
|
||||||
var errorCode = -1;
|
var errorCode = -1;
|
||||||
|
|
||||||
void OnCancelEvent(object sender, int timeout)
|
void OnCancelEvent(object sender, int timeout)
|
||||||
|
@ -132,7 +132,7 @@ await Task.WhenAll(instance.FinishedRunning().ContinueWith(t =>
|
||||||
private bool HandleCompletion(bool throwOnError, int exitCode, IReadOnlyList<string> errorData)
|
private bool HandleCompletion(bool throwOnError, int exitCode, IReadOnlyList<string> errorData)
|
||||||
{
|
{
|
||||||
if (throwOnError && exitCode != 0)
|
if (throwOnError && exitCode != 0)
|
||||||
throw new FFMpegProcessException(exitCode, string.Join("\n", errorData));
|
throw new FFMpegException(FFMpegExceptionType.Process, $"ffmpeg exited with non-zero exit-code ({exitCode} - {string.Join("\n", errorData)})", null, string.Join("\n", errorData));
|
||||||
|
|
||||||
_onPercentageProgress?.Invoke(100.0);
|
_onPercentageProgress?.Invoke(100.0);
|
||||||
if (_totalTimespan.HasValue) _onTimeProgress?.Invoke(_totalTimespan.Value);
|
if (_totalTimespan.HasValue) _onTimeProgress?.Invoke(_totalTimespan.Value);
|
||||||
|
@ -140,16 +140,17 @@ private bool HandleCompletion(bool throwOnError, int exitCode, IReadOnlyList<str
|
||||||
return exitCode == 0;
|
return exitCode == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Instance PrepareInstance(out CancellationTokenSource cancellationTokenSource)
|
private Instance PrepareInstance(FFOptions ffMpegOptions,
|
||||||
|
out CancellationTokenSource cancellationTokenSource)
|
||||||
{
|
{
|
||||||
FFMpegHelper.RootExceptionCheck();
|
FFMpegHelper.RootExceptionCheck();
|
||||||
FFMpegHelper.VerifyFFMpegExists();
|
FFMpegHelper.VerifyFFMpegExists(ffMpegOptions);
|
||||||
var startInfo = new ProcessStartInfo
|
var startInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = FFMpegOptions.Options.FFMpegBinary(),
|
FileName = GlobalFFOptions.GetFFMpegBinaryPath(ffMpegOptions),
|
||||||
Arguments = _ffMpegArguments.Text,
|
Arguments = _ffMpegArguments.Text,
|
||||||
StandardOutputEncoding = FFMpegOptions.Options.Encoding,
|
StandardOutputEncoding = ffMpegOptions.Encoding,
|
||||||
StandardErrorEncoding = FFMpegOptions.Options.Encoding,
|
StandardErrorEncoding = ffMpegOptions.Encoding,
|
||||||
};
|
};
|
||||||
var instance = new Instance(startInfo);
|
var instance = new Instance(startInfo);
|
||||||
cancellationTokenSource = new CancellationTokenSource();
|
cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
|
|
||||||
namespace FFMpegCore
|
namespace FFMpegCore
|
||||||
{
|
{
|
||||||
public sealed class FFMpegArguments : FFMpegOptionsBase
|
public sealed class FFMpegArguments : FFMpegArgumentsBase
|
||||||
{
|
{
|
||||||
private readonly FFMpegGlobalOptions _globalOptions = new FFMpegGlobalOptions();
|
private readonly FFMpegGlobalArguments _globalArguments = new FFMpegGlobalArguments();
|
||||||
|
|
||||||
private FFMpegArguments() { }
|
private FFMpegArguments() { }
|
||||||
|
|
||||||
public string Text => string.Join(" ", _globalOptions.Arguments.Concat(Arguments).Select(arg => arg.Text));
|
public string Text => string.Join(" ", _globalArguments.Arguments.Concat(Arguments).Select(arg => arg.Text));
|
||||||
|
|
||||||
public static FFMpegArguments FromConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments);
|
public static FFMpegArguments FromConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments);
|
||||||
public static FFMpegArguments FromDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new DemuxConcatArgument(filePaths), addArguments);
|
public static FFMpegArguments FromDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new DemuxConcatArgument(filePaths), addArguments);
|
||||||
|
@ -26,9 +26,9 @@ private FFMpegArguments() { }
|
||||||
public static FFMpegArguments FromPipeInput(IPipeSource sourcePipe, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputPipeArgument(sourcePipe), addArguments);
|
public static FFMpegArguments FromPipeInput(IPipeSource sourcePipe, Action<FFMpegArgumentOptions>? addArguments = null) => new FFMpegArguments().WithInput(new InputPipeArgument(sourcePipe), addArguments);
|
||||||
|
|
||||||
|
|
||||||
public FFMpegArguments WithGlobalOptions(Action<FFMpegGlobalOptions> configureOptions)
|
public FFMpegArguments WithGlobalOptions(Action<FFMpegGlobalArguments> configureOptions)
|
||||||
{
|
{
|
||||||
configureOptions(_globalOptions);
|
configureOptions(_globalArguments);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
namespace FFMpegCore
|
namespace FFMpegCore
|
||||||
{
|
{
|
||||||
public abstract class FFMpegOptionsBase
|
public abstract class FFMpegArgumentsBase
|
||||||
{
|
{
|
||||||
internal readonly List<IArgument> Arguments = new List<IArgument>();
|
internal readonly List<IArgument> Arguments = new List<IArgument>();
|
||||||
}
|
}
|
18
FFMpegCore/FFMpeg/FFMpegGlobalArguments.cs
Normal file
18
FFMpegCore/FFMpeg/FFMpegGlobalArguments.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
using FFMpegCore.Arguments;
|
||||||
|
|
||||||
|
namespace FFMpegCore
|
||||||
|
{
|
||||||
|
public sealed class FFMpegGlobalArguments : FFMpegArgumentsBase
|
||||||
|
{
|
||||||
|
internal FFMpegGlobalArguments() { }
|
||||||
|
|
||||||
|
public FFMpegGlobalArguments WithVerbosityLevel(VerbosityLevel verbosityLevel = VerbosityLevel.Error) => WithOption(new VerbosityLevelArgument(verbosityLevel));
|
||||||
|
|
||||||
|
private FFMpegGlobalArguments WithOption(IArgument argument)
|
||||||
|
{
|
||||||
|
Arguments.Add(argument);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,18 +0,0 @@
|
||||||
using FFMpegCore.Arguments;
|
|
||||||
|
|
||||||
namespace FFMpegCore
|
|
||||||
{
|
|
||||||
public sealed class FFMpegGlobalOptions : FFMpegOptionsBase
|
|
||||||
{
|
|
||||||
internal FFMpegGlobalOptions() { }
|
|
||||||
|
|
||||||
public FFMpegGlobalOptions WithVerbosityLevel(VerbosityLevel verbosityLevel = VerbosityLevel.Error) => WithOption(new VerbosityLevelArgument(verbosityLevel));
|
|
||||||
|
|
||||||
private FFMpegGlobalOptions WithOption(IArgument argument)
|
|
||||||
{
|
|
||||||
Arguments.Add(argument);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
namespace FFMpegCore
|
|
||||||
{
|
|
||||||
public class FFMpegOptions
|
|
||||||
{
|
|
||||||
private static readonly string ConfigFile = "ffmpeg.config.json";
|
|
||||||
private static readonly string DefaultRoot = "";
|
|
||||||
private static readonly string DefaultTemp = Path.GetTempPath();
|
|
||||||
private static readonly Dictionary<string, string> DefaultExtensionsOverrides = new Dictionary<string, string>
|
|
||||||
{
|
|
||||||
{ "mpegts", ".ts" },
|
|
||||||
};
|
|
||||||
|
|
||||||
public static FFMpegOptions Options { get; private set; } = new FFMpegOptions();
|
|
||||||
|
|
||||||
public static void Configure(Action<FFMpegOptions> optionsAction)
|
|
||||||
{
|
|
||||||
optionsAction?.Invoke(Options);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Configure(FFMpegOptions options)
|
|
||||||
{
|
|
||||||
Options = options ?? throw new ArgumentNullException(nameof(options));
|
|
||||||
}
|
|
||||||
|
|
||||||
static FFMpegOptions()
|
|
||||||
{
|
|
||||||
if (File.Exists(ConfigFile))
|
|
||||||
{
|
|
||||||
Options = JsonSerializer.Deserialize<FFMpegOptions>(File.ReadAllText(ConfigFile))!;
|
|
||||||
foreach (var pair in DefaultExtensionsOverrides)
|
|
||||||
if (!Options.ExtensionOverrides.ContainsKey(pair.Key)) Options.ExtensionOverrides.Add(pair.Key, pair.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string RootDirectory { get; set; } = DefaultRoot;
|
|
||||||
public string TempDirectory { get; set; } = DefaultTemp;
|
|
||||||
public bool UseCache { get; set; } = true;
|
|
||||||
public Encoding Encoding { get; set; } = Encoding.Default;
|
|
||||||
|
|
||||||
public string FFMpegBinary() => FFBinary("FFMpeg");
|
|
||||||
|
|
||||||
public string FFProbeBinary() => FFBinary("FFProbe");
|
|
||||||
|
|
||||||
public Dictionary<string, string> ExtensionOverrides { get; private set; } = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
private static string FFBinary(string name)
|
|
||||||
{
|
|
||||||
var ffName = name.ToLowerInvariant();
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
||||||
ffName += ".exe";
|
|
||||||
|
|
||||||
var target = Environment.Is64BitProcess ? "x64" : "x86";
|
|
||||||
if (Directory.Exists(Path.Combine(Options.RootDirectory, target)))
|
|
||||||
ffName = Path.Combine(target, ffName);
|
|
||||||
|
|
||||||
return Path.Combine(Options.RootDirectory, ffName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
37
FFMpegCore/FFOptions.cs
Normal file
37
FFMpegCore/FFOptions.cs
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FFMpegCore
|
||||||
|
{
|
||||||
|
public class FFOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Folder container ffmpeg and ffprobe binaries. Leave empty if ffmpeg and ffprobe are present in PATH
|
||||||
|
/// </summary>
|
||||||
|
public string BinaryFolder { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Folder used for temporary files necessary for static methods on FFMpeg class
|
||||||
|
/// </summary>
|
||||||
|
public string TemporaryFilesFolder { get; set; } = Path.GetTempPath();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Encoding used for parsing stdout/stderr on ffmpeg and ffprobe processes
|
||||||
|
/// </summary>
|
||||||
|
public Encoding Encoding { get; set; } = Encoding.Default;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
///
|
||||||
|
/// </summary>
|
||||||
|
public Dictionary<string, string> ExtensionOverrides { get; set; } = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
{ "mpegts", ".ts" },
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to cache calls to get ffmpeg codec, pixel- and container-formats
|
||||||
|
/// </summary>
|
||||||
|
public bool UseCache { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,32 +12,32 @@ namespace FFMpegCore
|
||||||
{
|
{
|
||||||
public static class FFProbe
|
public static class FFProbe
|
||||||
{
|
{
|
||||||
public static IMediaAnalysis Analyse(string filePath, int outputCapacity = int.MaxValue)
|
public static IMediaAnalysis Analyse(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
|
||||||
{
|
{
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
|
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
|
||||||
|
|
||||||
using var instance = PrepareInstance(filePath, outputCapacity);
|
using var instance = PrepareInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
var exitCode = instance.BlockUntilFinished();
|
var exitCode = instance.BlockUntilFinished();
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
throw new FFProbeProcessException(exitCode, string.Join("\n", instance.ErrorData));
|
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
|
||||||
|
|
||||||
return ParseOutput(instance);
|
return ParseOutput(instance);
|
||||||
}
|
}
|
||||||
public static IMediaAnalysis Analyse(Uri uri, int outputCapacity = int.MaxValue)
|
public static IMediaAnalysis Analyse(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
|
||||||
{
|
{
|
||||||
using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity);
|
using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
var exitCode = instance.BlockUntilFinished();
|
var exitCode = instance.BlockUntilFinished();
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
throw new FFProbeProcessException(exitCode, string.Join("\n", instance.ErrorData));
|
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
|
||||||
|
|
||||||
return ParseOutput(instance);
|
return ParseOutput(instance);
|
||||||
}
|
}
|
||||||
public static IMediaAnalysis Analyse(Stream stream, int outputCapacity = int.MaxValue)
|
public static IMediaAnalysis Analyse(Stream stream, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
|
||||||
{
|
{
|
||||||
var streamPipeSource = new StreamPipeSource(stream);
|
var streamPipeSource = new StreamPipeSource(stream);
|
||||||
var pipeArgument = new InputPipeArgument(streamPipeSource);
|
var pipeArgument = new InputPipeArgument(streamPipeSource);
|
||||||
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity);
|
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
pipeArgument.Pre();
|
pipeArgument.Pre();
|
||||||
|
|
||||||
var task = instance.FinishedRunning();
|
var task = instance.FinishedRunning();
|
||||||
|
@ -52,30 +52,30 @@ public static IMediaAnalysis Analyse(Stream stream, int outputCapacity = int.Max
|
||||||
}
|
}
|
||||||
var exitCode = task.ConfigureAwait(false).GetAwaiter().GetResult();
|
var exitCode = task.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
throw new FFProbeProcessException(exitCode, string.Join("\n", instance.ErrorData));
|
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({exitCode} - {string.Join("\n", instance.ErrorData)})", null, string.Join("\n", instance.ErrorData));
|
||||||
|
|
||||||
return ParseOutput(instance);
|
return ParseOutput(instance);
|
||||||
}
|
}
|
||||||
public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, int outputCapacity = int.MaxValue)
|
public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
|
||||||
{
|
{
|
||||||
if (!File.Exists(filePath))
|
if (!File.Exists(filePath))
|
||||||
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
|
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
|
||||||
|
|
||||||
using var instance = PrepareInstance(filePath, outputCapacity);
|
using var instance = PrepareInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
await instance.FinishedRunning().ConfigureAwait(false);
|
await instance.FinishedRunning().ConfigureAwait(false);
|
||||||
return ParseOutput(instance);
|
return ParseOutput(instance);
|
||||||
}
|
}
|
||||||
public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, int outputCapacity = int.MaxValue)
|
public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
|
||||||
{
|
{
|
||||||
using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity);
|
using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
await instance.FinishedRunning().ConfigureAwait(false);
|
await instance.FinishedRunning().ConfigureAwait(false);
|
||||||
return ParseOutput(instance);
|
return ParseOutput(instance);
|
||||||
}
|
}
|
||||||
public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, int outputCapacity = int.MaxValue)
|
public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
|
||||||
{
|
{
|
||||||
var streamPipeSource = new StreamPipeSource(stream);
|
var streamPipeSource = new StreamPipeSource(stream);
|
||||||
var pipeArgument = new InputPipeArgument(streamPipeSource);
|
var pipeArgument = new InputPipeArgument(streamPipeSource);
|
||||||
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity);
|
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
pipeArgument.Pre();
|
pipeArgument.Pre();
|
||||||
|
|
||||||
var task = instance.FinishedRunning();
|
var task = instance.FinishedRunning();
|
||||||
|
@ -112,12 +112,12 @@ private static IMediaAnalysis ParseOutput(Instance instance)
|
||||||
return new MediaAnalysis(ffprobeAnalysis);
|
return new MediaAnalysis(ffprobeAnalysis);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Instance PrepareInstance(string filePath, int outputCapacity)
|
private static Instance PrepareInstance(string filePath, int outputCapacity, FFOptions ffOptions)
|
||||||
{
|
{
|
||||||
FFProbeHelper.RootExceptionCheck();
|
FFProbeHelper.RootExceptionCheck();
|
||||||
FFProbeHelper.VerifyFFProbeExists();
|
FFProbeHelper.VerifyFFProbeExists(ffOptions);
|
||||||
var arguments = $"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"";
|
var arguments = $"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"";
|
||||||
var instance = new Instance(FFMpegOptions.Options.FFProbeBinary(), arguments) {DataBufferCapacity = outputCapacity};
|
var instance = new Instance(GlobalFFOptions.GetFFProbeBinaryPath(), arguments) {DataBufferCapacity = outputCapacity};
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
52
FFMpegCore/GlobalFFOptions.cs
Normal file
52
FFMpegCore/GlobalFFOptions.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace FFMpegCore
|
||||||
|
{
|
||||||
|
public static class GlobalFFOptions
|
||||||
|
{
|
||||||
|
private static readonly string ConfigFile = "ffmpeg.config.json";
|
||||||
|
|
||||||
|
public static FFOptions Current { get; private set; }
|
||||||
|
static GlobalFFOptions()
|
||||||
|
{
|
||||||
|
if (File.Exists(ConfigFile))
|
||||||
|
{
|
||||||
|
Current = JsonSerializer.Deserialize<FFOptions>(File.ReadAllText(ConfigFile))!;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Current = new FFOptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Configure(Action<FFOptions> optionsAction)
|
||||||
|
{
|
||||||
|
optionsAction?.Invoke(Current);
|
||||||
|
}
|
||||||
|
public static void Configure(FFOptions ffOptions)
|
||||||
|
{
|
||||||
|
Current = ffOptions ?? throw new ArgumentNullException(nameof(ffOptions));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static string GetFFMpegBinaryPath(FFOptions? ffOptions = null) => GetFFBinaryPath("FFMpeg", ffOptions ?? Current);
|
||||||
|
|
||||||
|
public static string GetFFProbeBinaryPath(FFOptions? ffOptions = null) => GetFFBinaryPath("FFProbe", ffOptions ?? Current);
|
||||||
|
|
||||||
|
private static string GetFFBinaryPath(string name, FFOptions ffOptions)
|
||||||
|
{
|
||||||
|
var ffName = name.ToLowerInvariant();
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
ffName += ".exe";
|
||||||
|
|
||||||
|
var target = Environment.Is64BitProcess ? "x64" : "x86";
|
||||||
|
if (Directory.Exists(Path.Combine(ffOptions.BinaryFolder, target)))
|
||||||
|
ffName = Path.Combine(target, ffName);
|
||||||
|
|
||||||
|
return Path.Combine(ffOptions.BinaryFolder, ffName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,17 +31,17 @@ public static void ExtensionExceptionCheck(string filename, string extension)
|
||||||
|
|
||||||
public static void RootExceptionCheck()
|
public static void RootExceptionCheck()
|
||||||
{
|
{
|
||||||
if (FFMpegOptions.Options.RootDirectory == null)
|
if (GlobalFFOptions.Current.BinaryFolder == null)
|
||||||
throw new FFMpegException(FFMpegExceptionType.Dependency,
|
throw new FFOptionsException("FFMpeg root is not configured in app config. Missing key 'BinaryFolder'.");
|
||||||
"FFMpeg root is not configured in app config. Missing key 'ffmpegRoot'.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyFFMpegExists()
|
public static void VerifyFFMpegExists(FFOptions ffMpegOptions)
|
||||||
{
|
{
|
||||||
if (_ffmpegVerified) return;
|
if (_ffmpegVerified) return;
|
||||||
var (exitCode, _) = Instance.Finish(FFMpegOptions.Options.FFMpegBinary(), "-version");
|
var (exitCode, _) = Instance.Finish(GlobalFFOptions.GetFFMpegBinaryPath(ffMpegOptions), "-version");
|
||||||
_ffmpegVerified = exitCode == 0;
|
_ffmpegVerified = exitCode == 0;
|
||||||
if (!_ffmpegVerified) throw new FFMpegException(FFMpegExceptionType.Operation, "ffmpeg was not found on your system");
|
if (!_ffmpegVerified)
|
||||||
|
throw new FFMpegException(FFMpegExceptionType.Operation, "ffmpeg was not found on your system");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,18 +20,17 @@ public static int Gcd(int first, int second)
|
||||||
|
|
||||||
public static void RootExceptionCheck()
|
public static void RootExceptionCheck()
|
||||||
{
|
{
|
||||||
if (FFMpegOptions.Options.RootDirectory == null)
|
if (GlobalFFOptions.Current.BinaryFolder == null)
|
||||||
throw new FFMpegException(FFMpegExceptionType.Dependency,
|
throw new FFOptionsException("FFProbe root is not configured in app config. Missing key 'BinaryFolder'.");
|
||||||
"FFProbe root is not configured in app config. Missing key 'ffmpegRoot'.");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void VerifyFFProbeExists()
|
public static void VerifyFFProbeExists(FFOptions ffMpegOptions)
|
||||||
{
|
{
|
||||||
if (_ffprobeVerified) return;
|
if (_ffprobeVerified) return;
|
||||||
var (exitCode, _) = Instance.Finish(FFMpegOptions.Options.FFProbeBinary(), "-version");
|
var (exitCode, _) = Instance.Finish(GlobalFFOptions.GetFFProbeBinaryPath(ffMpegOptions), "-version");
|
||||||
_ffprobeVerified = exitCode == 0;
|
_ffprobeVerified = exitCode == 0;
|
||||||
if (!_ffprobeVerified) throw new FFMpegException(FFMpegExceptionType.Operation, "ffprobe was not found on your system");
|
if (!_ffprobeVerified)
|
||||||
|
throw new FFMpegException(FFMpegExceptionType.Operation, "ffprobe was not found on your system");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue