mirror of
https://github.com/rosenbjerg/FFMpegCore.git
synced 2024-11-10 00:24:14 +01:00
Merge pull request #351 from keg247/sample-aspect-ratio
Add SampleAspectRatio property to VideoStream
Former-commit-id: 9727ec5cfe
This commit is contained in:
commit
b032af6405
4 changed files with 39 additions and 32 deletions
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using FFMpegCore.Test.Resources;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FFMpegCore.Test.Resources;
|
|
||||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
||||||
|
|
||||||
namespace FFMpegCore.Test
|
namespace FFMpegCore.Test
|
||||||
{
|
{
|
||||||
|
@ -24,7 +24,7 @@ public async Task Audio_FromStream_Duration()
|
||||||
public void FrameAnalysis_Sync()
|
public void FrameAnalysis_Sync()
|
||||||
{
|
{
|
||||||
var frameAnalysis = FFProbe.GetFrames(TestResources.WebmVideo);
|
var frameAnalysis = FFProbe.GetFrames(TestResources.WebmVideo);
|
||||||
|
|
||||||
Assert.AreEqual(90, frameAnalysis.Frames.Count);
|
Assert.AreEqual(90, frameAnalysis.Frames.Count);
|
||||||
Assert.IsTrue(frameAnalysis.Frames.All(f => f.PixelFormat == "yuv420p"));
|
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.Height == 360));
|
||||||
|
@ -36,7 +36,7 @@ public void FrameAnalysis_Sync()
|
||||||
public async Task FrameAnalysis_Async()
|
public async Task FrameAnalysis_Async()
|
||||||
{
|
{
|
||||||
var frameAnalysis = await FFProbe.GetFramesAsync(TestResources.WebmVideo);
|
var frameAnalysis = await FFProbe.GetFramesAsync(TestResources.WebmVideo);
|
||||||
|
|
||||||
Assert.AreEqual(90, frameAnalysis.Frames.Count);
|
Assert.AreEqual(90, frameAnalysis.Frames.Count);
|
||||||
Assert.IsTrue(frameAnalysis.Frames.All(f => f.PixelFormat == "yuv420p"));
|
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.Height == 360));
|
||||||
|
@ -55,12 +55,12 @@ public async Task PacketAnalysis_Async()
|
||||||
Assert.AreEqual(1362, packets.Last().Size);
|
Assert.AreEqual(1362, packets.Last().Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void PacketAnalysis_Sync()
|
public void PacketAnalysis_Sync()
|
||||||
{
|
{
|
||||||
var packets = FFProbe.GetPackets(TestResources.WebmVideo).Packets;
|
var packets = FFProbe.GetPackets(TestResources.WebmVideo).Packets;
|
||||||
|
|
||||||
Assert.AreEqual(96, packets.Count);
|
Assert.AreEqual(96, packets.Count);
|
||||||
Assert.IsTrue(packets.All(f => f.CodecType == "video"));
|
Assert.IsTrue(packets.All(f => f.CodecType == "video"));
|
||||||
Assert.AreEqual("K_", packets[0].Flags);
|
Assert.AreEqual("K_", packets[0].Flags);
|
||||||
|
@ -74,9 +74,9 @@ public void PacketAnalysisAudioVideo_Sync()
|
||||||
|
|
||||||
Assert.AreEqual(216, packets.Count);
|
Assert.AreEqual(216, packets.Count);
|
||||||
var actual = packets.Select(f => f.CodecType).Distinct().ToList();
|
var actual = packets.Select(f => f.CodecType).Distinct().ToList();
|
||||||
var expected = new List<string> {"audio", "video"};
|
var expected = new List<string> { "audio", "video" };
|
||||||
CollectionAssert.AreEquivalent(expected, actual);
|
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(75, packets.Count(t => t.CodecType == "video"));
|
||||||
Assert.AreEqual(141, packets.Count(t => t.CodecType == "audio"));
|
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"));
|
var fileAnalysis = await FFProbe.AnalyseAsync(new Uri("https://github.com/rosenbjerg/FFMpegCore/raw/master/FFMpegCore.Test/Resources/input_3sec.webm"));
|
||||||
Assert.IsNotNull(fileAnalysis);
|
Assert.IsNotNull(fileAnalysis);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void Probe_Success()
|
public void Probe_Success()
|
||||||
{
|
{
|
||||||
var info = FFProbe.Analyse(TestResources.Mp4Video);
|
var info = FFProbe.Analyse(TestResources.Mp4Video);
|
||||||
Assert.AreEqual(3, info.Duration.Seconds);
|
Assert.AreEqual(3, info.Duration.Seconds);
|
||||||
|
|
||||||
Assert.AreEqual("5.1", info.PrimaryAudioStream!.ChannelLayout);
|
Assert.AreEqual("5.1", info.PrimaryAudioStream!.ChannelLayout);
|
||||||
Assert.AreEqual(6, info.PrimaryAudioStream.Channels);
|
Assert.AreEqual(6, info.PrimaryAudioStream.Channels);
|
||||||
Assert.AreEqual("AAC (Advanced Audio Coding)", info.PrimaryAudioStream.CodecLongName);
|
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(48000, info.PrimaryAudioStream.SampleRateHz);
|
||||||
Assert.AreEqual("mp4a", info.PrimaryAudioStream.CodecTagString);
|
Assert.AreEqual("mp4a", info.PrimaryAudioStream.CodecTagString);
|
||||||
Assert.AreEqual("0x6134706d", info.PrimaryAudioStream.CodecTag);
|
Assert.AreEqual("0x6134706d", info.PrimaryAudioStream.CodecTag);
|
||||||
|
|
||||||
Assert.AreEqual(1471810, info.PrimaryVideoStream!.BitRate);
|
Assert.AreEqual(1471810, info.PrimaryVideoStream!.BitRate);
|
||||||
Assert.AreEqual(16, info.PrimaryVideoStream.DisplayAspectRatio.Width);
|
Assert.AreEqual(16, info.PrimaryVideoStream.DisplayAspectRatio.Width);
|
||||||
Assert.AreEqual(9, info.PrimaryVideoStream.DisplayAspectRatio.Height);
|
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("yuv420p", info.PrimaryVideoStream.PixelFormat);
|
||||||
Assert.AreEqual(1280, info.PrimaryVideoStream.Width);
|
Assert.AreEqual(1280, info.PrimaryVideoStream.Width);
|
||||||
Assert.AreEqual(720, info.PrimaryVideoStream.Height);
|
Assert.AreEqual(720, info.PrimaryVideoStream.Height);
|
||||||
|
@ -137,7 +139,7 @@ public void Probe_Success()
|
||||||
Assert.AreEqual("avc1", info.PrimaryVideoStream.CodecTagString);
|
Assert.AreEqual("avc1", info.PrimaryVideoStream.CodecTagString);
|
||||||
Assert.AreEqual("0x31637661", info.PrimaryVideoStream.CodecTag);
|
Assert.AreEqual("0x31637661", info.PrimaryVideoStream.CodecTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod, Timeout(10000)]
|
[TestMethod, Timeout(10000)]
|
||||||
public async Task Probe_Async_Success()
|
public async Task Probe_Async_Success()
|
||||||
{
|
{
|
||||||
|
|
|
@ -7,40 +7,40 @@ public class FFProbeAnalysis
|
||||||
{
|
{
|
||||||
[JsonPropertyName("streams")]
|
[JsonPropertyName("streams")]
|
||||||
public List<FFProbeStream> Streams { get; set; } = null!;
|
public List<FFProbeStream> Streams { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("format")]
|
[JsonPropertyName("format")]
|
||||||
public Format Format { get; set; } = null!;
|
public Format Format { get; set; } = null!;
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public IReadOnlyList<string> ErrorData { get; set; } = new List<string>();
|
public IReadOnlyList<string> ErrorData { get; set; } = new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FFProbeStream : ITagsContainer, IDispositionContainer
|
public class FFProbeStream : ITagsContainer, IDispositionContainer
|
||||||
{
|
{
|
||||||
[JsonPropertyName("index")]
|
[JsonPropertyName("index")]
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("avg_frame_rate")]
|
[JsonPropertyName("avg_frame_rate")]
|
||||||
public string AvgFrameRate { get; set; } = null!;
|
public string AvgFrameRate { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("bits_per_raw_sample")]
|
[JsonPropertyName("bits_per_raw_sample")]
|
||||||
public string BitsPerRawSample { get; set; } = null!;
|
public string BitsPerRawSample { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("bit_rate")]
|
[JsonPropertyName("bit_rate")]
|
||||||
public string BitRate { get; set; } = null!;
|
public string BitRate { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("channels")]
|
[JsonPropertyName("channels")]
|
||||||
public int? Channels { get; set; }
|
public int? Channels { get; set; }
|
||||||
|
|
||||||
[JsonPropertyName("channel_layout")]
|
[JsonPropertyName("channel_layout")]
|
||||||
public string ChannelLayout { get; set; } = null!;
|
public string ChannelLayout { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("codec_type")]
|
[JsonPropertyName("codec_type")]
|
||||||
public string CodecType { get; set; } = null!;
|
public string CodecType { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("codec_name")]
|
[JsonPropertyName("codec_name")]
|
||||||
public string CodecName { get; set; } = null!;
|
public string CodecName { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("codec_long_name")]
|
[JsonPropertyName("codec_long_name")]
|
||||||
public string CodecLongName { get; set; } = null!;
|
public string CodecLongName { get; set; } = null!;
|
||||||
|
|
||||||
|
@ -53,6 +53,9 @@ public class FFProbeStream : ITagsContainer, IDispositionContainer
|
||||||
[JsonPropertyName("display_aspect_ratio")]
|
[JsonPropertyName("display_aspect_ratio")]
|
||||||
public string DisplayAspectRatio { get; set; } = null!;
|
public string DisplayAspectRatio { get; set; } = null!;
|
||||||
|
|
||||||
|
[JsonPropertyName("sample_aspect_ratio")]
|
||||||
|
public string SampleAspectRatio { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("duration")]
|
[JsonPropertyName("duration")]
|
||||||
public string Duration { get; set; } = null!;
|
public string Duration { get; set; } = null!;
|
||||||
|
|
||||||
|
@ -67,10 +70,10 @@ public class FFProbeStream : ITagsContainer, IDispositionContainer
|
||||||
|
|
||||||
[JsonPropertyName("r_frame_rate")]
|
[JsonPropertyName("r_frame_rate")]
|
||||||
public string FrameRate { get; set; } = null!;
|
public string FrameRate { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("pix_fmt")]
|
[JsonPropertyName("pix_fmt")]
|
||||||
public string PixelFormat { get; set; } = null!;
|
public string PixelFormat { get; set; } = null!;
|
||||||
|
|
||||||
[JsonPropertyName("sample_rate")]
|
[JsonPropertyName("sample_rate")]
|
||||||
public string SampleRate { get; set; } = null!;
|
public string SampleRate { get; set; } = null!;
|
||||||
|
|
||||||
|
@ -135,7 +138,7 @@ public static class TagExtensions
|
||||||
return tagValue;
|
return tagValue;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string? GetLanguage(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "language");
|
public static string? GetLanguage(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "language");
|
||||||
public static string? GetCreationTime(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "creation_time ");
|
public static string? GetCreationTime(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "creation_time ");
|
||||||
public static string? GetRotate(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "rotate");
|
public static string? GetRotate(this ITagsContainer tagsContainer) => TryGetTagValue(tagsContainer, "rotate");
|
||||||
|
|
|
@ -15,7 +15,7 @@ internal MediaAnalysis(FFProbeAnalysis analysis)
|
||||||
SubtitleStreams = analysis.Streams.Where(stream => stream.CodecType == "subtitle").Select(ParseSubtitleStream).ToList();
|
SubtitleStreams = analysis.Streams.Where(stream => stream.CodecType == "subtitle").Select(ParseSubtitleStream).ToList();
|
||||||
ErrorData = analysis.ErrorData;
|
ErrorData = analysis.ErrorData;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaFormat ParseFormat(Format analysisFormat)
|
private MediaFormat ParseFormat(Format analysisFormat)
|
||||||
{
|
{
|
||||||
return new MediaFormat
|
return new MediaFormat
|
||||||
|
@ -38,7 +38,7 @@ private MediaFormat ParseFormat(Format analysisFormat)
|
||||||
}.Max();
|
}.Max();
|
||||||
|
|
||||||
public MediaFormat Format { get; }
|
public MediaFormat Format { get; }
|
||||||
|
|
||||||
public AudioStream? PrimaryAudioStream => AudioStreams.OrderBy(stream => stream.Index).FirstOrDefault();
|
public AudioStream? PrimaryAudioStream => AudioStreams.OrderBy(stream => stream.Index).FirstOrDefault();
|
||||||
public VideoStream? PrimaryVideoStream => VideoStreams.OrderBy(stream => stream.Index).FirstOrDefault();
|
public VideoStream? PrimaryVideoStream => VideoStreams.OrderBy(stream => stream.Index).FirstOrDefault();
|
||||||
public SubtitleStream? PrimarySubtitleStream => SubtitleStreams.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<AudioStream> AudioStreams { get; }
|
public List<AudioStream> AudioStreams { get; }
|
||||||
public List<SubtitleStream> SubtitleStreams { get; }
|
public List<SubtitleStream> SubtitleStreams { get; }
|
||||||
public IReadOnlyList<string> ErrorData { get; }
|
public IReadOnlyList<string> ErrorData { get; }
|
||||||
|
|
||||||
private VideoStream ParseVideoStream(FFProbeStream stream)
|
private VideoStream ParseVideoStream(FFProbeStream stream)
|
||||||
{
|
{
|
||||||
return new VideoStream
|
return new VideoStream
|
||||||
|
@ -61,6 +61,7 @@ private VideoStream ParseVideoStream(FFProbeStream stream)
|
||||||
CodecTag = stream.CodecTag,
|
CodecTag = stream.CodecTag,
|
||||||
CodecTagString = stream.CodecTagString,
|
CodecTagString = stream.CodecTagString,
|
||||||
DisplayAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.DisplayAspectRatio, ':'),
|
DisplayAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.DisplayAspectRatio, ':'),
|
||||||
|
SampleAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.SampleAspectRatio, ':'),
|
||||||
Duration = MediaAnalysisUtils.ParseDuration(stream),
|
Duration = MediaAnalysisUtils.ParseDuration(stream),
|
||||||
FrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.FrameRate, '/')),
|
FrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.FrameRate, '/')),
|
||||||
Height = stream.Height ?? 0,
|
Height = stream.Height ?? 0,
|
||||||
|
@ -141,11 +142,11 @@ public static double ParseDoubleInvariant(string line) =>
|
||||||
|
|
||||||
public static int ParseIntInvariant(string line) =>
|
public static int ParseIntInvariant(string line) =>
|
||||||
int.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
|
int.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
public static long ParseLongInvariant(string line) =>
|
public static long ParseLongInvariant(string line) =>
|
||||||
long.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
|
long.Parse(line, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
|
||||||
public static TimeSpan ParseDuration(string duration)
|
public static TimeSpan ParseDuration(string duration)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(duration))
|
if (!string.IsNullOrEmpty(duration))
|
||||||
|
|
|
@ -7,6 +7,7 @@ public class VideoStream : MediaStream
|
||||||
public double AvgFrameRate { get; set; }
|
public double AvgFrameRate { get; set; }
|
||||||
public int BitsPerRawSample { get; set; }
|
public int BitsPerRawSample { get; set; }
|
||||||
public (int Width, int Height) DisplayAspectRatio { 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 string Profile { get; set; } = null!;
|
||||||
public int Width { get; set; }
|
public int Width { get; set; }
|
||||||
public int Height { get; set; }
|
public int Height { get; set; }
|
||||||
|
|
Loading…
Reference in a new issue