Adding support for ffprobe show frames

Former-commit-id: 93131a7cd0
This commit is contained in:
Andrew Morgan 2021-09-24 10:23:59 +01:00
parent feaeb7478e
commit dbccc116fe
2 changed files with 85 additions and 0 deletions

View file

@ -25,6 +25,18 @@ public static IMediaAnalysis Analyse(string filePath, int outputCapacity = int.M
return ParseOutput(instance); return ParseOutput(instance);
} }
public static FFProbeFrames GetFrames(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
if (!File.Exists(filePath))
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
using var instance = PrepareProbeInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
var exitCode = instance.BlockUntilFinished();
if (exitCode != 0)
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 ParseFramesOutput(instance);
}
public static IMediaAnalysis Analyse(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null) public static IMediaAnalysis Analyse(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{ {
using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current); using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
@ -66,6 +78,16 @@ public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, int outpu
await instance.FinishedRunning().ConfigureAwait(false); await instance.FinishedRunning().ConfigureAwait(false);
return ParseOutput(instance); return ParseOutput(instance);
} }
public static async Task<FFProbeFrames> GetFramesAsync(string filePath, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{
if (!File.Exists(filePath))
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
using var instance = PrepareProbeInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
await instance.FinishedRunning().ConfigureAwait(false);
return ParseFramesOutput(instance);
}
public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null) public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, int outputCapacity = int.MaxValue, FFOptions? ffOptions = null)
{ {
using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current); using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
@ -112,6 +134,17 @@ private static IMediaAnalysis ParseOutput(Instance instance)
return new MediaAnalysis(ffprobeAnalysis); return new MediaAnalysis(ffprobeAnalysis);
} }
private static FFProbeFrames ParseFramesOutput(Instance instance)
{
var json = string.Join(string.Empty, instance.OutputData);
var ffprobeAnalysis = JsonSerializer.Deserialize<FFProbeFrames>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString
}) ;
return ffprobeAnalysis;
}
private static Instance PrepareInstance(string filePath, int outputCapacity, FFOptions ffOptions) private static Instance PrepareInstance(string filePath, int outputCapacity, FFOptions ffOptions)
{ {
@ -126,5 +159,18 @@ private static Instance PrepareInstance(string filePath, int outputCapacity, FFO
var instance = new Instance(startInfo) { DataBufferCapacity = outputCapacity }; var instance = new Instance(startInfo) { DataBufferCapacity = outputCapacity };
return instance; return instance;
} }
private static Instance PrepareProbeInstance(string filePath, int outputCapacity, FFOptions ffOptions)
{
FFProbeHelper.RootExceptionCheck();
FFProbeHelper.VerifyFFProbeExists(ffOptions);
var arguments = $"-loglevel error -print_format json -show_frames -v quiet -sexagesimal \"{filePath}\"";
var startInfo = new ProcessStartInfo(GlobalFFOptions.GetFFProbeBinaryPath(), arguments)
{
StandardOutputEncoding = ffOptions.Encoding,
StandardErrorEncoding = ffOptions.Encoding
};
var instance = new Instance(startInfo) { DataBufferCapacity = outputCapacity };
return instance;
}
} }
} }

View file

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;
namespace FFMpegCore
{
public class Frame
{
public string media_type { get; set; }
public int stream_index { get; set; }
public int key_frame { get; set; }
public long pkt_pts { get; set; }
public string pkt_pts_time { get; set; }
public long pkt_dts { get; set; }
public string pkt_dts_time { get; set; }
public long best_effort_timestamp { get; set; }
public string best_effort_timestamp_time { get; set; }
public int pkt_duration { get; set; }
public string pkt_duration_time { get; set; }
public long pkt_pos { get; set; }
public int pkt_size { get; set; }
public long width { get; set; }
public long height { get; set; }
public string pix_fmt { get; set; }
public string pict_type { get; set; }
public long coded_picture_number { get; set; }
public long display_picture_number { get; set; }
public int interlaced_frame { get; set; }
public int top_field_first { get; set; }
public int repeat_pict { get; set; }
public string chroma_location { get; set; }
}
public class FFProbeFrames
{
public List<Frame> frames { get; set; }
}
}