Support cancellationtoken on async ffprobe calls #299

This commit is contained in:
Malte Rosenbjerg 2022-03-24 20:34:25 +01:00
parent 2133d31021
commit da251e99ad

View file

@ -2,6 +2,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text.Json; using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFMpegCore.Arguments; using FFMpegCore.Arguments;
using FFMpegCore.Exceptions; using FFMpegCore.Exceptions;
@ -15,38 +16,33 @@ public static class FFProbe
{ {
public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null) public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = processArguments.StartAndWaitForExit(); var result = processArguments.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData));
return ParseOutput(result); return ParseOutput(result);
} }
public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null) public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = instance.StartAndWaitForExit(); var result = instance.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData));
return ParseFramesOutput(result); return ParseFramesOutput(result);
} }
public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null) public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = instance.StartAndWaitForExit(); var result = instance.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData));
return ParsePacketsOutput(result); return ParsePacketsOutput(result);
} }
@ -55,8 +51,7 @@ public static IMediaAnalysis Analyse(Uri uri, FFOptions? ffOptions = null)
{ {
var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current);
var result = instance.StartAndWaitForExit(); var result = instance.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData));
return ParseOutput(result); return ParseOutput(result);
} }
@ -78,64 +73,59 @@ public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null)
pipeArgument.Post(); pipeArgument.Post();
} }
var result = task.ConfigureAwait(false).GetAwaiter().GetResult(); var result = task.ConfigureAwait(false).GetAwaiter().GetResult();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData));
return ParseOutput(result); return ParseOutput(result);
} }
public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, FFOptions? ffOptions = null)
public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData));
return ParseOutput(result); return ParseOutput(result);
} }
public static async Task<FFProbeFrames> GetFramesAsync(string filePath, FFOptions? ffOptions = null) public static async Task<FFProbeFrames> GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
return ParseFramesOutput(result); return ParseFramesOutput(result);
} }
public static async Task<FFProbePackets> GetPacketsAsync(string filePath, FFOptions? ffOptions = null) public static async Task<FFProbePackets> GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
return ParsePacketsOutput(result); return ParsePacketsOutput(result);
} }
public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, FFOptions? ffOptions = null) public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current);
var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData));
return ParseOutput(result); return ParseOutput(result);
} }
public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions? ffOptions = null) public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
var streamPipeSource = new StreamPipeSource(stream); var streamPipeSource = new StreamPipeSource(stream);
var pipeArgument = new InputPipeArgument(streamPipeSource); var pipeArgument = new InputPipeArgument(streamPipeSource);
var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current);
pipeArgument.Pre(); pipeArgument.Pre();
var task = instance.StartAndWaitForExitAsync(); var task = instance.StartAndWaitForExitAsync(cancellationToken);
try try
{ {
await pipeArgument.During().ConfigureAwait(false); await pipeArgument.During(cancellationToken).ConfigureAwait(false);
} }
catch(IOException) catch(IOException)
{ {
@ -145,8 +135,7 @@ public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions?
pipeArgument.Post(); pipeArgument.Post();
} }
var result = await task.ConfigureAwait(false); var result = await task.ConfigureAwait(false);
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFProbeProcessException($"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", result.ErrorData);
pipeArgument.Post(); pipeArgument.Post();
return ParseOutput(result); return ParseOutput(result);
@ -189,6 +178,22 @@ private static FFProbePackets ParsePacketsOutput(IProcessResult instance)
return ffprobeAnalysis; return ffprobeAnalysis;
} }
private static void ThrowIfInputFileDoesNotExist(string filePath)
{
if (!File.Exists(filePath))
{
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
}
}
private static void ThrowIfExitCodeNotZero(IProcessResult result)
{
if (result.ExitCode != 0)
{
var message = $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})";
throw new FFMpegException(FFMpegExceptionType.Process, message, null, string.Join("\n", result.ErrorData));
}
}
private static ProcessArguments PrepareStreamAnalysisInstance(string filePath, FFOptions ffOptions) private static ProcessArguments PrepareStreamAnalysisInstance(string filePath, FFOptions ffOptions)
=> PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"", ffOptions); => PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"", ffOptions);