Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions FFMpegCore.Test/FFProbeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,31 @@ public void FrameAnalysis_Sync()
Assert.IsTrue(frameAnalysis.Frames.All(f => f.MediaType == "video"));
}

[TestMethod]
public void FrameAnalysis_FromStream_Sync()
{
using var stream = File.OpenRead(TestResources.WebmVideo);
var frameAnalysis = FFProbe.GetFrames(stream);

Assert.HasCount(90, frameAnalysis.Frames);
Assert.IsTrue(frameAnalysis.Frames.All(f => f.PixelFormat == "yuv420p"));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.Height == 360));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.Width == 640));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.MediaType == "video"));
}

[TestMethod]
public void FrameAnalysis_FromUri_Sync()
{
var frameAnalysis = FFProbe.GetFrames(new Uri(Path.GetFullPath(TestResources.WebmVideo)));

Assert.HasCount(90, frameAnalysis.Frames);
Assert.IsTrue(frameAnalysis.Frames.All(f => f.PixelFormat == "yuv420p"));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.Height == 360));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.Width == 640));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.MediaType == "video"));
}

[TestMethod]
public async Task FrameAnalysis_Async()
{
Expand All @@ -42,6 +67,19 @@ public async Task FrameAnalysis_Async()
Assert.IsTrue(frameAnalysis.Frames.All(f => f.MediaType == "video"));
}

[TestMethod]
public async Task FrameAnalysis_FromStream_Async()
{
using var stream = File.OpenRead(TestResources.WebmVideo);
var frameAnalysis = await FFProbe.GetFramesAsync(stream, cancellationToken: TestContext.CancellationToken);

Assert.HasCount(90, frameAnalysis.Frames);
Assert.IsTrue(frameAnalysis.Frames.All(f => f.PixelFormat == "yuv420p"));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.Height == 360));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.Width == 640));
Assert.IsTrue(frameAnalysis.Frames.All(f => f.MediaType == "video"));
}

[TestMethod]
public async Task PacketAnalysis_Async()
{
Expand Down
147 changes: 64 additions & 83 deletions FFMpegCore/FFProbe/FFProbe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,160 +13,141 @@ public static class FFProbe
{
public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null, string? customArguments = null)
{
ThrowIfInputFileDoesNotExist(filePath);

var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = processArguments.StartAndWaitForExit();
ThrowIfExitCodeNotZero(result);

return ParseOutput(result);
return AnalyseAsync(filePath, ffOptions, CancellationToken.None, customArguments).ConfigureAwait(false).GetAwaiter().GetResult();
}

public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null, string? customArguments = null)
public static IMediaAnalysis Analyse(Uri uri, FFOptions? ffOptions = null, string? customArguments = null)
{
ThrowIfInputFileDoesNotExist(filePath);

var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = instance.StartAndWaitForExit();
ThrowIfExitCodeNotZero(result);
return AnalyseAsync(uri, ffOptions, CancellationToken.None, customArguments).ConfigureAwait(false).GetAwaiter().GetResult();
}

return ParseFramesOutput(result);
public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null, string? customArguments = null)
{
return AnalyseAsync(stream, ffOptions, CancellationToken.None, customArguments).ConfigureAwait(false).GetAwaiter().GetResult();
}

public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null, string? customArguments = null)
public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
{
ThrowIfInputFileDoesNotExist(filePath);

var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = instance.StartAndWaitForExit();
ThrowIfExitCodeNotZero(result);

return ParsePacketsOutput(result);
return await AnalyseCoreAsync(filePath, ffOptions, cancellationToken, customArguments).ConfigureAwait(false);
}

public static IMediaAnalysis Analyse(Uri uri, FFOptions? ffOptions = null, string? customArguments = null)
public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
{
var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = instance.StartAndWaitForExit();
ThrowIfExitCodeNotZero(result);

return ParseOutput(result);
return await AnalyseCoreAsync(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri, ffOptions, cancellationToken, customArguments).ConfigureAwait(false);
}

public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null, string? customArguments = null)
public static async Task<IMediaAnalysis> 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, customArguments);
pipeArgument.Pre();

var task = instance.StartAndWaitForExitAsync();
var task = AnalyseCoreAsync(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current, cancellationToken, customArguments);

pipeArgument.Pre();
try
{
pipeArgument.During().ConfigureAwait(false).GetAwaiter().GetResult();
await pipeArgument.During(cancellationToken).ConfigureAwait(false);
}
catch (IOException)
{
}
catch (IOException) { }
finally
{
pipeArgument.Post();
}

var result = task.ConfigureAwait(false).GetAwaiter().GetResult();
ThrowIfExitCodeNotZero(result);

return ParseOutput(result);
return await task.ConfigureAwait(false);
}

public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null, string? customArguments = null)
{
ThrowIfInputFileDoesNotExist(filePath);

var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
ThrowIfExitCodeNotZero(result);

return ParseOutput(result);
return GetFramesAsync(filePath, ffOptions, CancellationToken.None, customArguments).ConfigureAwait(false).GetAwaiter().GetResult();
}

public static FFProbeFrames GetFrames(Uri uri, FFOptions? ffOptions = null, string? customArguments = null)
{
var instance = PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = instance.StartAndWaitForExit();
ThrowIfExitCodeNotZero(result);

return ParseFramesOutput(result);
return GetFramesAsync(uri, ffOptions, CancellationToken.None, customArguments).ConfigureAwait(false).GetAwaiter().GetResult();
}

public static async Task<FFProbeFrames> GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
public static FFProbeFrames GetFrames(Stream stream, FFOptions? ffOptions = null, string? customArguments = null)
{
ThrowIfInputFileDoesNotExist(filePath);

var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
return ParseFramesOutput(result);
return GetFramesAsync(stream, ffOptions, CancellationToken.None, customArguments).ConfigureAwait(false).GetAwaiter().GetResult();
}

public static async Task<FFProbePackets> GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
public static async Task<FFProbeFrames> GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
{
ThrowIfInputFileDoesNotExist(filePath);

var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
return ParsePacketsOutput(result);
return await GetFramesCoreAsync(filePath, ffOptions, cancellationToken, customArguments).ConfigureAwait(false);
}

public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
public static async Task<FFProbeFrames> GetFramesAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
{
var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
ThrowIfExitCodeNotZero(result);

return ParseOutput(result);
return await GetFramesCoreAsync(uri.IsFile ? uri.LocalPath : uri.AbsoluteUri, ffOptions, cancellationToken, customArguments).ConfigureAwait(false);
}

public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
public static async Task<FFProbeFrames> GetFramesAsync(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, customArguments);
pipeArgument.Pre();

var task = instance.StartAndWaitForExitAsync(cancellationToken);
var task = GetFramesCoreAsync(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current, cancellationToken, customArguments);

pipeArgument.Pre();
try
{
await pipeArgument.During(cancellationToken).ConfigureAwait(false);
}
catch (IOException)
{
}
catch (IOException) { }
finally
{
pipeArgument.Post();
}

var result = await task.ConfigureAwait(false);
return await task.ConfigureAwait(false);
}

private static async Task<IMediaAnalysis> AnalyseCoreAsync(string inputPath, FFOptions? ffOptions, CancellationToken cancellationToken, string? customArguments)
{
var instance = PrepareStreamAnalysisInstance(inputPath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
ThrowIfExitCodeNotZero(result);

pipeArgument.Post();
return ParseOutput(result);
}

public static async Task<FFProbeFrames> GetFramesAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
private static async Task<FFProbeFrames> GetFramesCoreAsync(string inputPath, FFOptions? ffOptions, CancellationToken cancellationToken, string? customArguments)
{
var instance = PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current, customArguments);
var instance = PrepareFrameAnalysisInstance(inputPath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
ThrowIfExitCodeNotZero(result);

return ParseFramesOutput(result);
}

public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null, string? customArguments = null)
{
return GetPacketsAsync(filePath, ffOptions, CancellationToken.None, customArguments).ConfigureAwait(false).GetAwaiter().GetResult();
}

public static async Task<FFProbePackets> GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default,
string? customArguments = null)
{
ThrowIfInputFileDoesNotExist(filePath);

var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current, customArguments);
var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
return ParsePacketsOutput(result);
}

private static IMediaAnalysis ParseOutput(IProcessResult instance)
{
var json = string.Join(string.Empty, instance.OutputData);
Expand Down
Loading