mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 08:34:12 +01:00
parse ffprobes -show_packets output
This commit is contained in:
parent
0f82509c41
commit
239e2aef42
3 changed files with 124 additions and 0 deletions
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -50,6 +51,43 @@ public async Task FrameAnalysis_Async()
|
||||||
Assert.IsTrue(frameAnalysis.Frames.All(f => f.MediaType == "video"));
|
Assert.IsTrue(frameAnalysis.Frames.All(f => f.MediaType == "video"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public async Task PacketAnalysis_Async()
|
||||||
|
{
|
||||||
|
var packetAnalysis = await FFProbe.GetPacketsAsync(TestResources.WebmVideo);
|
||||||
|
var packets = packetAnalysis.Packets;
|
||||||
|
Assert.AreEqual(96, packets.Count);
|
||||||
|
Assert.IsTrue(packets.All(f => f.CodecType == "video"));
|
||||||
|
Assert.AreEqual("K_", packets[0].Flags);
|
||||||
|
Assert.AreEqual(1362, packets.Last().Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PacketAnalysis_Sync()
|
||||||
|
{
|
||||||
|
var packets = FFProbe.GetPackets(TestResources.WebmVideo).Packets;
|
||||||
|
|
||||||
|
Assert.AreEqual(96, packets.Count);
|
||||||
|
Assert.IsTrue(packets.All(f => f.CodecType == "video"));
|
||||||
|
Assert.AreEqual("K_", packets[0].Flags);
|
||||||
|
Assert.AreEqual(1362, packets.Last().Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void PacketAnalysisAudioVideo_Sync()
|
||||||
|
{
|
||||||
|
var packets = FFProbe.GetPackets(TestResources.Mp4Video).Packets;
|
||||||
|
|
||||||
|
Assert.AreEqual(216, packets.Count);
|
||||||
|
var actual = packets.Select(f => f.CodecType).Distinct().ToList();
|
||||||
|
var expected = new List<string> {"audio", "video"};
|
||||||
|
CollectionAssert.AreEquivalent(expected, actual);
|
||||||
|
Assert.IsTrue(packets.Where(t=>t.CodecType == "audio").All(f => f.Flags == "K_"));
|
||||||
|
Assert.AreEqual(75, packets.Count(t => t.CodecType == "video"));
|
||||||
|
Assert.AreEqual(141, packets.Count(t => t.CodecType == "audio"));
|
||||||
|
}
|
||||||
|
|
||||||
[DataTestMethod]
|
[DataTestMethod]
|
||||||
[DataRow("0:00:03.008000", 0, 0, 0, 3, 8)]
|
[DataRow("0:00:03.008000", 0, 0, 0, 3, 8)]
|
||||||
[DataRow("05:12:59.177", 0, 5, 12, 59, 177)]
|
[DataRow("05:12:59.177", 0, 5, 12, 59, 177)]
|
||||||
|
|
|
@ -37,6 +37,20 @@ public static FFProbeFrames GetFrames(string filePath, int outputCapacity = int.
|
||||||
|
|
||||||
return ParseFramesOutput(instance);
|
return ParseFramesOutput(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FFProbePackets GetPackets(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 = PreparePacketAnalysisInstance(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 ParsePacketsOutput(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 = PrepareStreamAnalysisInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
using var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
|
@ -91,6 +105,17 @@ public static async Task<FFProbeFrames> GetFramesAsync(string filePath, int outp
|
||||||
await instance.FinishedRunning().ConfigureAwait(false);
|
await instance.FinishedRunning().ConfigureAwait(false);
|
||||||
return ParseFramesOutput(instance);
|
return ParseFramesOutput(instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<FFProbePackets> GetPacketsAsync(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 = PreparePacketAnalysisInstance(filePath, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
|
await instance.FinishedRunning().ConfigureAwait(false);
|
||||||
|
return ParsePacketsOutput(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 = PrepareStreamAnalysisInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
using var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, outputCapacity, ffOptions ?? GlobalFFOptions.Current);
|
||||||
|
@ -152,11 +177,25 @@ private static FFProbeFrames ParseFramesOutput(Instance instance)
|
||||||
return ffprobeAnalysis;
|
return ffprobeAnalysis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FFProbePackets ParsePacketsOutput(Instance instance)
|
||||||
|
{
|
||||||
|
var json = string.Join(string.Empty, instance.OutputData);
|
||||||
|
var ffprobeAnalysis = JsonSerializer.Deserialize<FFProbePackets>(json, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString
|
||||||
|
}) ;
|
||||||
|
|
||||||
|
return ffprobeAnalysis;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Instance PrepareStreamAnalysisInstance(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);
|
=> PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"", outputCapacity, ffOptions);
|
||||||
private static Instance PrepareFrameAnalysisInstance(string filePath, int outputCapacity, FFOptions 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);
|
=> PrepareInstance($"-loglevel error -print_format json -show_frames -v quiet -sexagesimal \"{filePath}\"", outputCapacity, ffOptions);
|
||||||
|
private static Instance PreparePacketAnalysisInstance(string filePath, int outputCapacity, FFOptions ffOptions)
|
||||||
|
=> PrepareInstance($"-loglevel error -print_format json -show_packets -v quiet -sexagesimal \"{filePath}\"", outputCapacity, ffOptions);
|
||||||
|
|
||||||
private static Instance PrepareInstance(string arguments, int outputCapacity, FFOptions ffOptions)
|
private static Instance PrepareInstance(string arguments, int outputCapacity, FFOptions ffOptions)
|
||||||
{
|
{
|
||||||
|
|
47
FFMpegCore/FFProbe/PacketAnalysis.cs
Normal file
47
FFMpegCore/FFProbe/PacketAnalysis.cs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace FFMpegCore
|
||||||
|
{
|
||||||
|
public class FFProbePacketAnalysis
|
||||||
|
{
|
||||||
|
[JsonPropertyName("codec_type")]
|
||||||
|
public string CodecType { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("stream_index")]
|
||||||
|
public int StreamIndex { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("pts")]
|
||||||
|
public long Pts { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("pts_time")]
|
||||||
|
public string PtsTime { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("dts")]
|
||||||
|
public long Dts { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("dts_time")]
|
||||||
|
public string DtsTime { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("duration")]
|
||||||
|
public int Duration { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("duration_time")]
|
||||||
|
public string DurationTime { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("size")]
|
||||||
|
public int Size { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("pos")]
|
||||||
|
public long Pos { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("flags")]
|
||||||
|
public string Flags { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FFProbePackets
|
||||||
|
{
|
||||||
|
[JsonPropertyName("packets")]
|
||||||
|
public List<FFProbePacketAnalysis> Packets { get; set; }
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue