diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj
index 8b99510..e63c0af 100644
--- a/FFMpegCore.Test/FFMpegCore.Test.csproj
+++ b/FFMpegCore.Test/FFMpegCore.Test.csproj
@@ -42,6 +42,9 @@
PreserveNewest
+
+ PreserveNewest
+
PreserveNewest
diff --git a/FFMpegCore.Test/FFProbeTests.cs b/FFMpegCore.Test/FFProbeTests.cs
index cc8f85b..9b86202 100644
--- a/FFMpegCore.Test/FFProbeTests.cs
+++ b/FFMpegCore.Test/FFProbeTests.cs
@@ -134,6 +134,16 @@ public void Probe_Success()
Assert.AreEqual("0x31637661", info.PrimaryVideoStream.CodecTag);
}
+ [TestMethod]
+ public void Probe_Rotation()
+ {
+ var info = FFProbe.Analyse(TestResources.Mp4Video);
+ Assert.AreEqual(0, info.PrimaryVideoStream.Rotation);
+
+ info = FFProbe.Analyse(TestResources.Mp4VideoRotation);
+ Assert.AreEqual(90, info.PrimaryVideoStream.Rotation);
+ }
+
[TestMethod, Timeout(10000)]
public async Task Probe_Async_Success()
{
diff --git a/FFMpegCore.Test/Resources/TestResources.cs b/FFMpegCore.Test/Resources/TestResources.cs
index bf29960..de84080 100644
--- a/FFMpegCore.Test/Resources/TestResources.cs
+++ b/FFMpegCore.Test/Resources/TestResources.cs
@@ -13,6 +13,7 @@ public enum ImageType
public static class TestResources
{
public static readonly string Mp4Video = "./Resources/input_3sec.mp4";
+ public static readonly string Mp4VideoRotation = "./Resources/input_3sec_rotation_90deg.mp4";
public static readonly string WebmVideo = "./Resources/input_3sec.webm";
public static readonly string Mp4WithoutVideo = "./Resources/input_audio_only_10sec.mp4";
public static readonly string Mp4WithoutAudio = "./Resources/input_video_only_3sec.mp4";
diff --git a/FFMpegCore.Test/Resources/input_3sec_rotation_90deg.mp4 b/FFMpegCore.Test/Resources/input_3sec_rotation_90deg.mp4
new file mode 100644
index 0000000..c2a9ee2
Binary files /dev/null and b/FFMpegCore.Test/Resources/input_3sec_rotation_90deg.mp4 differ
diff --git a/FFMpegCore/FFProbe/FFProbeAnalysis.cs b/FFMpegCore/FFProbe/FFProbeAnalysis.cs
index ec58653..d65fc2d 100644
--- a/FFMpegCore/FFProbe/FFProbeAnalysis.cs
+++ b/FFMpegCore/FFProbe/FFProbeAnalysis.cs
@@ -1,4 +1,5 @@
-using System.Text.Json.Serialization;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
namespace FFMpegCore
{
@@ -84,6 +85,9 @@ public class FFProbeStream : ITagsContainer, IDispositionContainer
[JsonPropertyName("tags")]
public Dictionary Tags { get; set; } = null!;
+
+ [JsonPropertyName("side_data_list")]
+ public List> SideData { get; set; } = null!;
}
public class Format : ITagsContainer
diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs
index b6bc4a5..bfbc370 100644
--- a/FFMpegCore/FFProbe/MediaAnalysis.cs
+++ b/FFMpegCore/FFProbe/MediaAnalysis.cs
@@ -72,7 +72,7 @@ private VideoStream ParseVideoStream(FFProbeStream stream)
Width = stream.Width ?? 0,
Profile = stream.Profile,
PixelFormat = stream.PixelFormat,
- Rotation = (int)float.Parse(stream.GetRotate() ?? "0"),
+ Rotation = MediaAnalysisUtils.ParseRotation(stream),
Language = stream.GetLanguage(),
Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition),
Tags = stream.Tags.ToCaseInsensitive(),
@@ -196,6 +196,20 @@ public static TimeSpan ParseDuration(FFProbeStream ffProbeStream)
return ParseDuration(ffProbeStream.Duration);
}
+ public static int ParseRotation(FFProbeStream fFProbeStream)
+ {
+ var displayMatrixSideData = fFProbeStream.SideData?.Find(item => item.TryGetValue("side_data_type", out var rawSideDataType) && rawSideDataType.ToString() == "Display Matrix");
+
+ if (displayMatrixSideData?.TryGetValue("rotation", out var rawRotation) ?? false)
+ {
+ return (int)float.Parse(rawRotation.ToString());
+ }
+ else
+ {
+ return (int)float.Parse(fFProbeStream.GetRotate() ?? "0");
+ }
+ }
+
public static Dictionary? FormatDisposition(Dictionary? disposition)
{
if (disposition == null)