Minor improvements

Former-commit-id: 79bc918917
This commit is contained in:
Malte Rosenbjerg 2021-10-21 20:36:54 +02:00
parent dbccc116fe
commit 75fa1db64f
3 changed files with 112 additions and 51 deletions

View file

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FFMpegCore.Test.Resources;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -25,6 +26,30 @@ public async Task Audio_FromStream_Duration()
Assert.IsTrue(fileAnalysis.Duration == streamAnalysis.Duration);
}
[TestMethod]
public void FrameAnalysis_Sync()
{
var frameAnalysis = FFProbe.GetFrames(TestResources.WebmVideo);
Assert.AreEqual(90, frameAnalysis.Frames.Count);
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()
{
var frameAnalysis = await FFProbe.GetFramesAsync(TestResources.WebmVideo);
Assert.AreEqual(90, frameAnalysis.Frames.Count);
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"));
}
[DataTestMethod]
[DataRow("0:00:03.008000", 0, 0, 0, 3, 8)]
[DataRow("05:12:59.177", 0, 5, 12, 59, 177)]

View file

@ -18,7 +18,7 @@ public static IMediaAnalysis Analyse(string filePath, int outputCapacity = int.M
if (!File.Exists(filePath))
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
using var instance = PrepareInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
using var instance = PrepareStreamAnalysisInstance(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));
@ -30,7 +30,7 @@ public static FFProbeFrames GetFrames(string filePath, int outputCapacity = int.
if (!File.Exists(filePath))
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
using var instance = PrepareProbeInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
using var instance = PrepareFrameAnalysisInstance(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));
@ -39,7 +39,7 @@ public static FFProbeFrames GetFrames(string filePath, int outputCapacity = int.
}
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 = PrepareStreamAnalysisInstance(uri.AbsoluteUri, 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));
@ -50,7 +50,7 @@ public static IMediaAnalysis Analyse(Stream stream, int outputCapacity = int.Max
{
var streamPipeSource = new StreamPipeSource(stream);
var pipeArgument = new InputPipeArgument(streamPipeSource);
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
using var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
pipeArgument.Pre();
var task = instance.FinishedRunning();
@ -74,7 +74,7 @@ public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, int outpu
if (!File.Exists(filePath))
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
using var instance = PrepareInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
using var instance = PrepareStreamAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
await instance.FinishedRunning().ConfigureAwait(false);
return ParseOutput(instance);
}
@ -84,13 +84,13 @@ public static async Task<FFProbeFrames> GetFramesAsync(string filePath, int outp
if (!File.Exists(filePath))
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
using var instance = PrepareProbeInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
using var instance = PrepareFrameAnalysisInstance(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)
{
using var instance = PrepareInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
using var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
await instance.FinishedRunning().ConfigureAwait(false);
return ParseOutput(instance);
}
@ -98,7 +98,7 @@ public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, int outputC
{
var streamPipeSource = new StreamPipeSource(stream);
var pipeArgument = new InputPipeArgument(streamPipeSource);
using var instance = PrepareInstance(pipeArgument.PipePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
using var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
pipeArgument.Pre();
var task = instance.FinishedRunning();
@ -146,24 +146,16 @@ private static FFProbeFrames ParseFramesOutput(Instance instance)
return ffprobeAnalysis;
}
private static Instance PrepareInstance(string filePath, int outputCapacity, FFOptions ffOptions)
private static Instance PrepareStreamAnalysisInstance(string filePath, int outputCapacity, FFOptions ffOptions)
=> PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"", outputCapacity, ffOptions);
private static Instance PrepareFrameAnalysisInstance(string filePath, int outputCapacity, FFOptions ffOptions)
=> PrepareInstance($"-loglevel error -print_format json -show_frames -v quiet -sexagesimal \"{filePath}\"", outputCapacity, ffOptions);
private static Instance PrepareInstance(string arguments, int outputCapacity, FFOptions ffOptions)
{
FFProbeHelper.RootExceptionCheck();
FFProbeHelper.VerifyFFProbeExists(ffOptions);
var arguments = $"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"";
var startInfo = new ProcessStartInfo(GlobalFFOptions.GetFFProbeBinaryPath(), arguments)
{
StandardOutputEncoding = ffOptions.Encoding,
StandardErrorEncoding = ffOptions.Encoding
};
var instance = new Instance(startInfo) { DataBufferCapacity = outputCapacity };
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,

View file

@ -1,39 +1,83 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace FFMpegCore
{
public class Frame
public class FFProbeFrameAnalysis
{
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; }
[JsonPropertyName("media_type")]
public string MediaType { get; set; }
[JsonPropertyName("stream_index")]
public int StreamIndex { get; set; }
[JsonPropertyName("key_frame")]
public int KeyFrame { get; set; }
[JsonPropertyName("pkt_pts")]
public long PacketPts { get; set; }
[JsonPropertyName("pkt_pts_time")]
public string PacketPtsTime { get; set; }
[JsonPropertyName("pkt_dts")]
public long PacketDts { get; set; }
[JsonPropertyName("pkt_dts_time")]
public string PacketDtsTime { get; set; }
[JsonPropertyName("best_effort_timestamp")]
public long BestEffortTimestamp { get; set; }
[JsonPropertyName("best_effort_timestamp_time")]
public string BestEffortTimestampTime { get; set; }
[JsonPropertyName("pkt_duration")]
public int PacketDuration { get; set; }
[JsonPropertyName("pkt_duration_time")]
public string PacketDurationTime { get; set; }
[JsonPropertyName("pkt_pos")]
public long PacketPos { get; set; }
[JsonPropertyName("pkt_size")]
public int PacketSize { get; set; }
[JsonPropertyName("width")]
public long Width { get; set; }
[JsonPropertyName("height")]
public long Height { get; set; }
[JsonPropertyName("pix_fmt")]
public string PixelFormat { get; set; }
[JsonPropertyName("pict_type")]
public string PictureType { get; set; }
[JsonPropertyName("coded_picture_number")]
public long CodedPictureNumber { get; set; }
[JsonPropertyName("display_picture_number")]
public long DisplayPictureNumber { get; set; }
[JsonPropertyName("interlaced_frame")]
public int InterlacedFrame { get; set; }
[JsonPropertyName("top_field_first")]
public int TopFieldFirst { get; set; }
[JsonPropertyName("repeat_pict")]
public int RepeatPicture { get; set; }
[JsonPropertyName("chroma_location")]
public string ChromaLocation { get; set; }
}
public class FFProbeFrames
{
public List<Frame> frames { get; set; }
[JsonPropertyName("frames")]
public List<FFProbeFrameAnalysis> Frames { get; set; }
}
}