From 1dd2685aff75b1eaee43b8c14b99fb8a4408f1d8 Mon Sep 17 00:00:00 2001 From: keg247 <44041557+keg247@users.noreply.github.com> Date: Tue, 19 Jul 2022 16:16:42 -0400 Subject: [PATCH] Add SampleAspectRatio property to VideoStream Former-commit-id: 02de377093322db7027e6dcf55831479d2aec22d --- FFMpegCore.Test/FFProbeTests.cs | 28 ++++++++++++++------------ FFMpegCore/FFProbe/FFProbeAnalysis.cs | 29 +++++++++++++++------------ FFMpegCore/FFProbe/MediaAnalysis.cs | 13 ++++++------ FFMpegCore/FFProbe/VideoStream.cs | 1 + 4 files changed, 39 insertions(+), 32 deletions(-) diff --git a/FFMpegCore.Test/FFProbeTests.cs b/FFMpegCore.Test/FFProbeTests.cs index af7f08b..87e883c 100644 --- a/FFMpegCore.Test/FFProbeTests.cs +++ b/FFMpegCore.Test/FFProbeTests.cs @@ -1,10 +1,10 @@ -using System; +using FFMpegCore.Test.Resources; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; -using FFMpegCore.Test.Resources; -using Microsoft.VisualStudio.TestTools.UnitTesting; namespace FFMpegCore.Test { @@ -24,7 +24,7 @@ public async Task Audio_FromStream_Duration() 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)); @@ -36,7 +36,7 @@ public void FrameAnalysis_Sync() 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)); @@ -55,12 +55,12 @@ public async Task PacketAnalysis_Async() 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); @@ -74,9 +74,9 @@ public void PacketAnalysisAudioVideo_Sync() Assert.AreEqual(216, packets.Count); var actual = packets.Select(f => f.CodecType).Distinct().ToList(); - var expected = new List {"audio", "video"}; + var expected = new List { "audio", "video" }; CollectionAssert.AreEquivalent(expected, actual); - Assert.IsTrue(packets.Where(t=>t.CodecType == "audio").All(f => f.Flags == "K_")); + 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")); } @@ -105,13 +105,13 @@ public async Task Uri_Duration() var fileAnalysis = await FFProbe.AnalyseAsync(new Uri("https://github.com/rosenbjerg/FFMpegCore/raw/master/FFMpegCore.Test/Resources/input_3sec.webm")); Assert.IsNotNull(fileAnalysis); } - + [TestMethod] public void Probe_Success() { var info = FFProbe.Analyse(TestResources.Mp4Video); Assert.AreEqual(3, info.Duration.Seconds); - + Assert.AreEqual("5.1", info.PrimaryAudioStream!.ChannelLayout); Assert.AreEqual(6, info.PrimaryAudioStream.Channels); Assert.AreEqual("AAC (Advanced Audio Coding)", info.PrimaryAudioStream.CodecLongName); @@ -121,10 +121,12 @@ public void Probe_Success() Assert.AreEqual(48000, info.PrimaryAudioStream.SampleRateHz); Assert.AreEqual("mp4a", info.PrimaryAudioStream.CodecTagString); Assert.AreEqual("0x6134706d", info.PrimaryAudioStream.CodecTag); - + Assert.AreEqual(1471810, info.PrimaryVideoStream!.BitRate); Assert.AreEqual(16, info.PrimaryVideoStream.DisplayAspectRatio.Width); Assert.AreEqual(9, info.PrimaryVideoStream.DisplayAspectRatio.Height); + Assert.AreEqual(1, info.PrimaryVideoStream.SampleAspectRatio.Width); + Assert.AreEqual(1, info.PrimaryVideoStream.SampleAspectRatio.Height); Assert.AreEqual("yuv420p", info.PrimaryVideoStream.PixelFormat); Assert.AreEqual(1280, info.PrimaryVideoStream.Width); Assert.AreEqual(720, info.PrimaryVideoStream.Height); @@ -137,7 +139,7 @@ public void Probe_Success() Assert.AreEqual("avc1", info.PrimaryVideoStream.CodecTagString); Assert.AreEqual("0x31637661", info.PrimaryVideoStream.CodecTag); } - + [TestMethod, Timeout(10000)] public async Task Probe_Async_Success() { diff --git a/FFMpegCore/FFProbe/FFProbeAnalysis.cs b/FFMpegCore/FFProbe/FFProbeAnalysis.cs index b81d535..eb65bb2 100644 --- a/FFMpegCore/FFProbe/FFProbeAnalysis.cs +++ b/FFMpegCore/FFProbe/FFProbeAnalysis.cs @@ -7,40 +7,40 @@ public class FFProbeAnalysis { [JsonPropertyName("streams")] public List Streams { get; set; } = null!; - + [JsonPropertyName("format")] public Format Format { get; set; } = null!; - + [JsonIgnore] public IReadOnlyList ErrorData { get; set; } = new List(); } - + public class FFProbeStream : ITagsContainer, IDispositionContainer { [JsonPropertyName("index")] public int Index { get; set; } - + [JsonPropertyName("avg_frame_rate")] public string AvgFrameRate { get; set; } = null!; - + [JsonPropertyName("bits_per_raw_sample")] public string BitsPerRawSample { get; set; } = null!; - + [JsonPropertyName("bit_rate")] public string BitRate { get; set; } = null!; - + [JsonPropertyName("channels")] public int? Channels { get; set; } - + [JsonPropertyName("channel_layout")] public string ChannelLayout { get; set; } = null!; [JsonPropertyName("codec_type")] public string CodecType { get; set; } = null!; - + [JsonPropertyName("codec_name")] public string CodecName { get; set; } = null!; - + [JsonPropertyName("codec_long_name")] public string CodecLongName { get; set; } = null!; @@ -53,6 +53,9 @@ public class FFProbeStream : ITagsContainer, IDispositionContainer [JsonPropertyName("display_aspect_ratio")] public string DisplayAspectRatio { get; set; } = null!; + [JsonPropertyName("sample_aspect_ratio")] + public string SampleAspectRatio { get; set; } = null!; + [JsonPropertyName("duration")] public string Duration { get; set; } = null!; @@ -67,10 +70,10 @@ public class FFProbeStream : ITagsContainer, IDispositionContainer [JsonPropertyName("r_frame_rate")] public string FrameRate { get; set; } = null!; - + [JsonPropertyName("pix_fmt")] public string PixelFormat { get; set; } = null!; - + [JsonPropertyName("sample_rate")] public string SampleRate { get; set; } = null!; @@ -135,7 +138,7 @@ public static class TagExtensions return tagValue; return null; } - + public static string? GetLanguage(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "language"); public static string? GetCreationTime(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "creation_time "); public static string? GetRotate(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "rotate"); diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs index fd2b135..bb68c22 100644 --- a/FFMpegCore/FFProbe/MediaAnalysis.cs +++ b/FFMpegCore/FFProbe/MediaAnalysis.cs @@ -15,7 +15,7 @@ internal MediaAnalysis(FFProbeAnalysis analysis) SubtitleStreams = analysis.Streams.Where(stream => stream.CodecType == "subtitle").Select(ParseSubtitleStream).ToList(); ErrorData = analysis.ErrorData; } - + private MediaFormat ParseFormat(Format analysisFormat) { return new MediaFormat @@ -38,7 +38,7 @@ private MediaFormat ParseFormat(Format analysisFormat) }.Max(); public MediaFormat Format { get; } - + public AudioStream? PrimaryAudioStream => AudioStreams.OrderBy(stream => stream.Index).FirstOrDefault(); public VideoStream? PrimaryVideoStream => VideoStreams.OrderBy(stream => stream.Index).FirstOrDefault(); public SubtitleStream? PrimarySubtitleStream => SubtitleStreams.OrderBy(stream => stream.Index).FirstOrDefault(); @@ -47,7 +47,7 @@ private MediaFormat ParseFormat(Format analysisFormat) public List AudioStreams { get; } public List SubtitleStreams { get; } public IReadOnlyList ErrorData { get; } - + private VideoStream ParseVideoStream(FFProbeStream stream) { return new VideoStream @@ -61,6 +61,7 @@ private VideoStream ParseVideoStream(FFProbeStream stream) CodecTag = stream.CodecTag, CodecTagString = stream.CodecTagString, DisplayAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.DisplayAspectRatio, ':'), + SampleAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.SampleAspectRatio, ':'), Duration = MediaAnalysisUtils.ParseDuration(stream), FrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.FrameRate, '/')), Height = stream.Height ?? 0, @@ -141,11 +142,11 @@ public static double ParseDoubleInvariant(string line) => public static int ParseIntInvariant(string line) => int.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture); - + public static long ParseLongInvariant(string line) => long.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture); - - + + public static TimeSpan ParseDuration(string duration) { if (!string.IsNullOrEmpty(duration)) diff --git a/FFMpegCore/FFProbe/VideoStream.cs b/FFMpegCore/FFProbe/VideoStream.cs index a07cdd9..45d5105 100644 --- a/FFMpegCore/FFProbe/VideoStream.cs +++ b/FFMpegCore/FFProbe/VideoStream.cs @@ -7,6 +7,7 @@ public class VideoStream : MediaStream public double AvgFrameRate { get; set; } public int BitsPerRawSample { get; set; } public (int Width, int Height) DisplayAspectRatio { get; set; } + public (int Width, int Height) SampleAspectRatio { get; set; } public string Profile { get; set; } = null!; public int Width { get; set; } public int Height { get; set; }