diff --git a/FFMpegCore.Test/FFProbeTests.cs b/FFMpegCore.Test/FFProbeTests.cs index 30746df..a507078 100644 --- a/FFMpegCore.Test/FFProbeTests.cs +++ b/FFMpegCore.Test/FFProbeTests.cs @@ -236,5 +236,12 @@ public async Task Probe_Success_32BitWavBitDepth_Async() Assert.IsNotNull(info.PrimaryAudioStream); Assert.AreEqual(32, info.PrimaryAudioStream.BitDepth); } + + [TestMethod] + public void Probe_Success_Custom_Arguments() + { + var info = FFProbe.Analyse(TestResources.Mp4Video, customArguments: "-headers \"Hello: World\""); + Assert.AreEqual(3, info.Duration.Seconds); + } } } diff --git a/FFMpegCore/FFProbe/FFProbe.cs b/FFMpegCore/FFProbe/FFProbe.cs index d1032c6..ee5f5f5 100644 --- a/FFMpegCore/FFProbe/FFProbe.cs +++ b/FFMpegCore/FFProbe/FFProbe.cs @@ -10,52 +10,52 @@ namespace FFMpegCore { public static class FFProbe { - public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null) + public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null, string? customArguments = null) { ThrowIfInputFileDoesNotExist(filePath); - var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); + var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = processArguments.StartAndWaitForExit(); ThrowIfExitCodeNotZero(result); return ParseOutput(result); } - public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null) + public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null, string? customArguments = null) { ThrowIfInputFileDoesNotExist(filePath); - var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = instance.StartAndWaitForExit(); ThrowIfExitCodeNotZero(result); return ParseFramesOutput(result); } - public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null) + public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null, string? customArguments = null) { ThrowIfInputFileDoesNotExist(filePath); - var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); + var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = instance.StartAndWaitForExit(); ThrowIfExitCodeNotZero(result); return ParsePacketsOutput(result); } - public static IMediaAnalysis Analyse(Uri uri, FFOptions? ffOptions = null) + public static IMediaAnalysis Analyse(Uri uri, FFOptions? ffOptions = null, string? customArguments = null) { - var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = instance.StartAndWaitForExit(); ThrowIfExitCodeNotZero(result); return ParseOutput(result); } - public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null) + public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null, string? customArguments = null) { var streamPipeSource = new StreamPipeSource(stream); var pipeArgument = new InputPipeArgument(streamPipeSource); - var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current, customArguments); pipeArgument.Pre(); var task = instance.StartAndWaitForExitAsync(); @@ -75,57 +75,57 @@ public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null) return ParseOutput(result); } - public static async Task AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) + public static async Task AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default, string? customArguments = null) { ThrowIfInputFileDoesNotExist(filePath); - var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); ThrowIfExitCodeNotZero(result); return ParseOutput(result); } - public static FFProbeFrames GetFrames(Uri uri, FFOptions? ffOptions = null) + public static FFProbeFrames GetFrames(Uri uri, FFOptions? ffOptions = null, string? customArguments = null) { - var instance = PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = instance.StartAndWaitForExit(); ThrowIfExitCodeNotZero(result); return ParseFramesOutput(result); } - public static async Task GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) + public static async Task GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default, string? customArguments = null) { ThrowIfInputFileDoesNotExist(filePath); - var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); return ParseFramesOutput(result); } - public static async Task GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) + public static async Task GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default, string? customArguments = null) { ThrowIfInputFileDoesNotExist(filePath); - var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); + var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); return ParsePacketsOutput(result); } - public static async Task AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) + public static async Task AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default, string? customArguments = null) { - var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); ThrowIfExitCodeNotZero(result); return ParseOutput(result); } - public static async Task AnalyseAsync(Stream stream, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) + public static async Task AnalyseAsync(Stream stream, FFOptions? ffOptions = null, CancellationToken cancellationToken = default, string? customArguments = null) { var streamPipeSource = new StreamPipeSource(stream); var pipeArgument = new InputPipeArgument(streamPipeSource); - var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current, customArguments); pipeArgument.Pre(); var task = instance.StartAndWaitForExitAsync(cancellationToken); @@ -148,9 +148,9 @@ public static async Task AnalyseAsync(Stream stream, FFOptions? return ParseOutput(result); } - public static async Task GetFramesAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) + public static async Task GetFramesAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default, string? customArguments = null) { - var instance = PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); + var instance = PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); return ParseFramesOutput(result); } @@ -212,18 +212,18 @@ private static void ThrowIfExitCodeNotZero(IProcessResult result) } } - private static ProcessArguments PrepareStreamAnalysisInstance(string filePath, FFOptions ffOptions) - => PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams -show_chapters \"{filePath}\"", ffOptions); - private static ProcessArguments PrepareFrameAnalysisInstance(string filePath, FFOptions ffOptions) - => PrepareInstance($"-loglevel error -print_format json -show_frames -v quiet -sexagesimal \"{filePath}\"", ffOptions); - private static ProcessArguments PreparePacketAnalysisInstance(string filePath, FFOptions ffOptions) - => PrepareInstance($"-loglevel error -print_format json -show_packets -v quiet -sexagesimal \"{filePath}\"", ffOptions); + private static ProcessArguments PrepareStreamAnalysisInstance(string filePath, FFOptions ffOptions, string? customArguments) + => PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams -show_chapters \"{filePath}\"", ffOptions, customArguments); + private static ProcessArguments PrepareFrameAnalysisInstance(string filePath, FFOptions ffOptions, string? customArguments) + => PrepareInstance($"-loglevel error -print_format json -show_frames -v quiet -sexagesimal \"{filePath}\"", ffOptions, customArguments); + private static ProcessArguments PreparePacketAnalysisInstance(string filePath, FFOptions ffOptions, string? customArguments) + => PrepareInstance($"-loglevel error -print_format json -show_packets -v quiet -sexagesimal \"{filePath}\"", ffOptions, customArguments); - private static ProcessArguments PrepareInstance(string arguments, FFOptions ffOptions) + private static ProcessArguments PrepareInstance(string arguments, FFOptions ffOptions, string? customArguments) { FFProbeHelper.RootExceptionCheck(); FFProbeHelper.VerifyFFProbeExists(ffOptions); - var startInfo = new ProcessStartInfo(GlobalFFOptions.GetFFProbeBinaryPath(ffOptions), arguments) + var startInfo = new ProcessStartInfo(GlobalFFOptions.GetFFProbeBinaryPath(ffOptions), $"{arguments} {customArguments}") { StandardOutputEncoding = ffOptions.Encoding, StandardErrorEncoding = ffOptions.Encoding,