From 05839825e0ec9edb867dfb4279975529bba5e3aa Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 20:24:22 +0100 Subject: [PATCH 01/12] Wrap image size check in using block #304 --- FFMpegCore/FFMpeg/FFMpeg.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/FFMpegCore/FFMpeg/FFMpeg.cs b/FFMpegCore/FFMpeg/FFMpeg.cs index d227a2e..4e7d47a 100644 --- a/FFMpegCore/FFMpeg/FFMpeg.cs +++ b/FFMpegCore/FFMpeg/FFMpeg.cs @@ -247,7 +247,10 @@ public static bool Convert( public static bool PosterWithAudio(string image, string audio, string output) { FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4); - FFMpegHelper.ConversionSizeExceptionCheck(Image.FromFile(image)); + using (var imageFile = Image.FromFile(image)) + { + FFMpegHelper.ConversionSizeExceptionCheck(imageFile); + } return FFMpegArguments .FromFileInput(image, false, options => options From 2133d310217f760678fa28c8f5b8409b8e5d9c21 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 20:27:09 +0100 Subject: [PATCH 02/12] Expose avg_frame_rate as AverageFrameRate on VideoStream #300 --- FFMpegCore/FFProbe/FFProbeAnalysis.cs | 3 +++ FFMpegCore/FFProbe/MediaAnalysis.cs | 1 + FFMpegCore/FFProbe/VideoStream.cs | 1 + 3 files changed, 5 insertions(+) diff --git a/FFMpegCore/FFProbe/FFProbeAnalysis.cs b/FFMpegCore/FFProbe/FFProbeAnalysis.cs index 2177307..9967508 100644 --- a/FFMpegCore/FFProbe/FFProbeAnalysis.cs +++ b/FFMpegCore/FFProbe/FFProbeAnalysis.cs @@ -64,6 +64,9 @@ public class FFProbeStream : ITagsContainer, IDispositionContainer [JsonPropertyName("r_frame_rate")] public string FrameRate { get; set; } = null!; + + [JsonPropertyName("avg_frame_rate")] + public string AverageFrameRate { get; set; } = null!; [JsonPropertyName("pix_fmt")] public string PixelFormat { get; set; } = null!; diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs index a2db068..72fc3a9 100644 --- a/FFMpegCore/FFProbe/MediaAnalysis.cs +++ b/FFMpegCore/FFProbe/MediaAnalysis.cs @@ -61,6 +61,7 @@ private VideoStream ParseVideoStream(FFProbeStream stream) DisplayAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.DisplayAspectRatio, ':'), Duration = MediaAnalysisUtils.ParseDuration(stream), FrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.FrameRate, '/')), + AverageFrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.AverageFrameRate, '/')), Height = stream.Height ?? 0, Width = stream.Width ?? 0, Profile = stream.Profile, diff --git a/FFMpegCore/FFProbe/VideoStream.cs b/FFMpegCore/FFProbe/VideoStream.cs index 0bcfc09..8738212 100644 --- a/FFMpegCore/FFProbe/VideoStream.cs +++ b/FFMpegCore/FFProbe/VideoStream.cs @@ -13,6 +13,7 @@ public class VideoStream : MediaStream public double FrameRate { get; internal set; } public string PixelFormat { get; internal set; } = null!; public int Rotation { get; set; } + public double AverageFrameRate { get; set; } public PixelFormat GetPixelFormatInfo() => FFMpeg.GetPixelFormat(PixelFormat); } From da251e99ad7279085d9ea2d44642726ad2391c28 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 20:34:25 +0100 Subject: [PATCH 03/12] Support cancellationtoken on async ffprobe calls #299 --- FFMpegCore/FFProbe/FFProbe.cs | 83 +++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/FFMpegCore/FFProbe/FFProbe.cs b/FFMpegCore/FFProbe/FFProbe.cs index 75f0df1..cfd719e 100644 --- a/FFMpegCore/FFProbe/FFProbe.cs +++ b/FFMpegCore/FFProbe/FFProbe.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using FFMpegCore.Arguments; using FFMpegCore.Exceptions; @@ -15,38 +16,33 @@ public static class FFProbe { public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null) { - if (!File.Exists(filePath)) - throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'"); + ThrowIfInputFileDoesNotExist(filePath); var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var result = processArguments.StartAndWaitForExit(); - if (result.ExitCode != 0) - throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData)); + ThrowIfExitCodeNotZero(result); return ParseOutput(result); } + public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null) { - if (!File.Exists(filePath)) - throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'"); + ThrowIfInputFileDoesNotExist(filePath); var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var result = instance.StartAndWaitForExit(); - if (result.ExitCode != 0) - throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData)); + ThrowIfExitCodeNotZero(result); return ParseFramesOutput(result); } public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null) { - if (!File.Exists(filePath)) - throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'"); + ThrowIfInputFileDoesNotExist(filePath); var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var result = instance.StartAndWaitForExit(); - if (result.ExitCode != 0) - throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData)); + ThrowIfExitCodeNotZero(result); return ParsePacketsOutput(result); } @@ -55,8 +51,7 @@ public static IMediaAnalysis Analyse(Uri uri, FFOptions? ffOptions = null) { var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); var result = instance.StartAndWaitForExit(); - if (result.ExitCode != 0) - throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData)); + ThrowIfExitCodeNotZero(result); return ParseOutput(result); } @@ -78,64 +73,59 @@ public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null) pipeArgument.Post(); } var result = task.ConfigureAwait(false).GetAwaiter().GetResult(); - if (result.ExitCode != 0) - throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData)); + ThrowIfExitCodeNotZero(result); return ParseOutput(result); } - public static async Task AnalyseAsync(string filePath, FFOptions? ffOptions = null) + + public static async Task AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) { - if (!File.Exists(filePath)) - throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'"); + ThrowIfInputFileDoesNotExist(filePath); var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); - var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); - if (result.ExitCode != 0) - throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData)); + var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); + ThrowIfExitCodeNotZero(result); return ParseOutput(result); } - public static async Task GetFramesAsync(string filePath, FFOptions? ffOptions = null) + public static async Task GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) { - if (!File.Exists(filePath)) - throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'"); + ThrowIfInputFileDoesNotExist(filePath); var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); - var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); + var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); return ParseFramesOutput(result); } - public static async Task GetPacketsAsync(string filePath, FFOptions? ffOptions = null) + public static async Task GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) { - if (!File.Exists(filePath)) - throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'"); + ThrowIfInputFileDoesNotExist(filePath); var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); - var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); + var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); return ParsePacketsOutput(result); } - public static async Task AnalyseAsync(Uri uri, FFOptions? ffOptions = null) + public static async Task AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) { var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); - var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); - if (result.ExitCode != 0) - throw new FFMpegException(FFMpegExceptionType.Process, $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", null, string.Join("\n", result.ErrorData)); + var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false); + ThrowIfExitCodeNotZero(result); return ParseOutput(result); } - public static async Task AnalyseAsync(Stream stream, FFOptions? ffOptions = null) + public static async Task AnalyseAsync(Stream stream, FFOptions? ffOptions = null, CancellationToken cancellationToken = default) { var streamPipeSource = new StreamPipeSource(stream); var pipeArgument = new InputPipeArgument(streamPipeSource); var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current); pipeArgument.Pre(); - var task = instance.StartAndWaitForExitAsync(); + var task = instance.StartAndWaitForExitAsync(cancellationToken); try { - await pipeArgument.During().ConfigureAwait(false); + await pipeArgument.During(cancellationToken).ConfigureAwait(false); } catch(IOException) { @@ -145,8 +135,7 @@ public static async Task AnalyseAsync(Stream stream, FFOptions? pipeArgument.Post(); } var result = await task.ConfigureAwait(false); - if (result.ExitCode != 0) - throw new FFProbeProcessException($"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", result.ErrorData); + ThrowIfExitCodeNotZero(result); pipeArgument.Post(); return ParseOutput(result); @@ -189,6 +178,22 @@ private static FFProbePackets ParsePacketsOutput(IProcessResult instance) return ffprobeAnalysis; } + private static void ThrowIfInputFileDoesNotExist(string filePath) + { + if (!File.Exists(filePath)) + { + throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'"); + } + } + + private static void ThrowIfExitCodeNotZero(IProcessResult result) + { + if (result.ExitCode != 0) + { + var message = $"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})"; + throw new FFMpegException(FFMpegExceptionType.Process, message, null, string.Join("\n", result.ErrorData)); + } + } private static ProcessArguments PrepareStreamAnalysisInstance(string filePath, FFOptions ffOptions) => PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"", ffOptions); From fc86a64b9e75637652480f200a5e92dd5cfd42d0 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 20:37:27 +0100 Subject: [PATCH 04/12] Make properties on MediaStream classes for deserialization #296 --- FFMpegCore/FFProbe/AudioStream.cs | 8 ++++---- FFMpegCore/FFProbe/FFProbe.cs | 4 ++-- FFMpegCore/FFProbe/MediaStream.cs | 18 +++++++++--------- FFMpegCore/FFProbe/VideoStream.cs | 16 ++++++++-------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/FFMpegCore/FFProbe/AudioStream.cs b/FFMpegCore/FFProbe/AudioStream.cs index d6f4b33..50c5572 100644 --- a/FFMpegCore/FFProbe/AudioStream.cs +++ b/FFMpegCore/FFProbe/AudioStream.cs @@ -2,9 +2,9 @@ { public class AudioStream : MediaStream { - public int Channels { get; internal set; } - public string ChannelLayout { get; internal set; } = null!; - public int SampleRateHz { get; internal set; } - public string Profile { get; internal set; } = null!; + public int Channels { get; set; } + public string ChannelLayout { get; set; } = null!; + public int SampleRateHz { get; set; } + public string Profile { get; set; } = null!; } } \ No newline at end of file diff --git a/FFMpegCore/FFProbe/FFProbe.cs b/FFMpegCore/FFProbe/FFProbe.cs index cfd719e..15ad171 100644 --- a/FFMpegCore/FFProbe/FFProbe.cs +++ b/FFMpegCore/FFProbe/FFProbe.cs @@ -163,7 +163,7 @@ private static FFProbeFrames ParseFramesOutput(IProcessResult instance) NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString }) ; - return ffprobeAnalysis; + return ffprobeAnalysis!; } private static FFProbePackets ParsePacketsOutput(IProcessResult instance) @@ -175,7 +175,7 @@ private static FFProbePackets ParsePacketsOutput(IProcessResult instance) NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString }) ; - return ffprobeAnalysis; + return ffprobeAnalysis!; } private static void ThrowIfInputFileDoesNotExist(string filePath) diff --git a/FFMpegCore/FFProbe/MediaStream.cs b/FFMpegCore/FFProbe/MediaStream.cs index 68bc78f..ffab04b 100644 --- a/FFMpegCore/FFProbe/MediaStream.cs +++ b/FFMpegCore/FFProbe/MediaStream.cs @@ -5,18 +5,18 @@ namespace FFMpegCore { - public class MediaStream + public abstract class MediaStream { - public int Index { get; internal set; } - public string CodecName { get; internal set; } = null!; - public string CodecLongName { get; internal set; } = null!; + public int Index { get; set; } + public string CodecName { get; set; } = null!; + public string CodecLongName { get; set; } = null!; public string CodecTagString { get; set; } = null!; public string CodecTag { get; set; } = null!; - public long BitRate { get; internal set; } - public TimeSpan Duration { get; internal set; } - public string? Language { get; internal set; } - public Dictionary? Disposition { get; internal set; } - public Dictionary? Tags { get; internal set; } + public long BitRate { get; set; } + public TimeSpan Duration { get; set; } + public string? Language { get; set; } + public Dictionary? Disposition { get; set; } + public Dictionary? Tags { get; set; } public Codec GetCodecInfo() => FFMpeg.GetCodec(CodecName); } diff --git a/FFMpegCore/FFProbe/VideoStream.cs b/FFMpegCore/FFProbe/VideoStream.cs index 8738212..a07cdd9 100644 --- a/FFMpegCore/FFProbe/VideoStream.cs +++ b/FFMpegCore/FFProbe/VideoStream.cs @@ -4,14 +4,14 @@ namespace FFMpegCore { public class VideoStream : MediaStream { - public double AvgFrameRate { get; internal set; } - public int BitsPerRawSample { get; internal set; } - public (int Width, int Height) DisplayAspectRatio { get; internal set; } - public string Profile { get; internal set; } = null!; - public int Width { get; internal set; } - public int Height { get; internal set; } - public double FrameRate { get; internal set; } - public string PixelFormat { get; internal set; } = null!; + public double AvgFrameRate { get; set; } + public int BitsPerRawSample { get; set; } + public (int Width, int Height) DisplayAspectRatio { get; set; } + public string Profile { get; set; } = null!; + public int Width { get; set; } + public int Height { get; set; } + public double FrameRate { get; set; } + public string PixelFormat { get; set; } = null!; public int Rotation { get; set; } public double AverageFrameRate { get; set; } From 90155efe75c4bf704a8e7cf16de6e50620b39250 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 20:45:49 +0100 Subject: [PATCH 05/12] Make Tags and Disposition dictionaries case-insensivite #295 --- FFMpegCore/FFProbe/MediaAnalysis.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs index 72fc3a9..42cc5e5 100644 --- a/FFMpegCore/FFProbe/MediaAnalysis.cs +++ b/FFMpegCore/FFProbe/MediaAnalysis.cs @@ -25,7 +25,7 @@ private MediaFormat ParseFormat(Format analysisFormat) StreamCount = analysisFormat.NbStreams, ProbeScore = analysisFormat.ProbeScore, BitRate = long.Parse(analysisFormat.BitRate ?? "0"), - Tags = analysisFormat.Tags, + Tags = analysisFormat.Tags.ToCaseInsensitive(), }; } @@ -69,7 +69,7 @@ private VideoStream ParseVideoStream(FFProbeStream stream) Rotation = (int)float.Parse(stream.GetRotate() ?? "0"), Language = stream.GetLanguage(), Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition), - Tags = stream.Tags, + Tags = stream.Tags.ToCaseInsensitive(), }; } @@ -90,7 +90,7 @@ private AudioStream ParseAudioStream(FFProbeStream stream) Profile = stream.Profile, Language = stream.GetLanguage(), Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition), - Tags = stream.Tags, + Tags = stream.Tags.ToCaseInsensitive(), }; } @@ -105,15 +105,20 @@ private SubtitleStream ParseSubtitleStream(FFProbeStream stream) Duration = MediaAnalysisUtils.ParseDuration(stream), Language = stream.GetLanguage(), Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition), - Tags = stream.Tags, + Tags = stream.Tags.ToCaseInsensitive(), }; } + } public static class MediaAnalysisUtils { private static readonly Regex DurationRegex = new Regex(@"^(\d+):(\d{1,2}):(\d{1,2})\.(\d{1,3})", RegexOptions.Compiled); + internal static Dictionary ToCaseInsensitive(this Dictionary dictionary) + { + return dictionary.ToDictionary(tag => tag.Key, tag => tag.Value, StringComparer.OrdinalIgnoreCase); + } public static double DivideRatio((double, double) ratio) => ratio.Item1 / ratio.Item2; public static (int, int) ParseRatioInt(string input, char separator) @@ -184,7 +189,7 @@ public static TimeSpan ParseDuration(FFProbeStream ffProbeStream) return null; } - var result = new Dictionary(disposition.Count); + var result = new Dictionary(disposition.Count, StringComparer.Ordinal); foreach (var pair in disposition) { From 787804c3a288578e57c501eabeaaf767269248eb Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 20:46:02 +0100 Subject: [PATCH 06/12] Clean warnings --- FFMpegCore/FFProbe/FrameAnalysis.cs | 18 +++++++++--------- FFMpegCore/FFProbe/PacketAnalysis.cs | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/FFMpegCore/FFProbe/FrameAnalysis.cs b/FFMpegCore/FFProbe/FrameAnalysis.cs index a22cd24..08e5037 100644 --- a/FFMpegCore/FFProbe/FrameAnalysis.cs +++ b/FFMpegCore/FFProbe/FrameAnalysis.cs @@ -6,7 +6,7 @@ namespace FFMpegCore public class FFProbeFrameAnalysis { [JsonPropertyName("media_type")] - public string MediaType { get; set; } + public string MediaType { get; set; } = null!; [JsonPropertyName("stream_index")] public int StreamIndex { get; set; } @@ -18,25 +18,25 @@ public class FFProbeFrameAnalysis public long PacketPts { get; set; } [JsonPropertyName("pkt_pts_time")] - public string PacketPtsTime { get; set; } + public string PacketPtsTime { get; set; } = null!; [JsonPropertyName("pkt_dts")] public long PacketDts { get; set; } [JsonPropertyName("pkt_dts_time")] - public string PacketDtsTime { get; set; } + public string PacketDtsTime { get; set; } = null!; [JsonPropertyName("best_effort_timestamp")] public long BestEffortTimestamp { get; set; } [JsonPropertyName("best_effort_timestamp_time")] - public string BestEffortTimestampTime { get; set; } + public string BestEffortTimestampTime { get; set; } = null!; [JsonPropertyName("pkt_duration")] public int PacketDuration { get; set; } [JsonPropertyName("pkt_duration_time")] - public string PacketDurationTime { get; set; } + public string PacketDurationTime { get; set; } = null!; [JsonPropertyName("pkt_pos")] public long PacketPos { get; set; } @@ -51,10 +51,10 @@ public class FFProbeFrameAnalysis public long Height { get; set; } [JsonPropertyName("pix_fmt")] - public string PixelFormat { get; set; } + public string PixelFormat { get; set; } = null!; [JsonPropertyName("pict_type")] - public string PictureType { get; set; } + public string PictureType { get; set; } = null!; [JsonPropertyName("coded_picture_number")] public long CodedPictureNumber { get; set; } @@ -72,12 +72,12 @@ public class FFProbeFrameAnalysis public int RepeatPicture { get; set; } [JsonPropertyName("chroma_location")] - public string ChromaLocation { get; set; } + public string ChromaLocation { get; set; } = null!; } public class FFProbeFrames { [JsonPropertyName("frames")] - public List Frames { get; set; } + public List Frames { get; set; } = null!; } } diff --git a/FFMpegCore/FFProbe/PacketAnalysis.cs b/FFMpegCore/FFProbe/PacketAnalysis.cs index d4da0f5..babe403 100644 --- a/FFMpegCore/FFProbe/PacketAnalysis.cs +++ b/FFMpegCore/FFProbe/PacketAnalysis.cs @@ -6,7 +6,7 @@ namespace FFMpegCore public class FFProbePacketAnalysis { [JsonPropertyName("codec_type")] - public string CodecType { get; set; } + public string CodecType { get; set; } = null!; [JsonPropertyName("stream_index")] public int StreamIndex { get; set; } @@ -15,19 +15,19 @@ public class FFProbePacketAnalysis public long Pts { get; set; } [JsonPropertyName("pts_time")] - public string PtsTime { get; set; } + public string PtsTime { get; set; } = null!; [JsonPropertyName("dts")] public long Dts { get; set; } [JsonPropertyName("dts_time")] - public string DtsTime { get; set; } + public string DtsTime { get; set; } = null!; [JsonPropertyName("duration")] public int Duration { get; set; } [JsonPropertyName("duration_time")] - public string DurationTime { get; set; } + public string DurationTime { get; set; } = null!; [JsonPropertyName("size")] public int Size { get; set; } @@ -36,12 +36,12 @@ public class FFProbePacketAnalysis public long Pos { get; set; } [JsonPropertyName("flags")] - public string Flags { get; set; } + public string Flags { get; set; } = null!; } public class FFProbePackets { [JsonPropertyName("packets")] - public List Packets { get; set; } + public List Packets { get; set; } = null!; } } From c817381139b247842cd44f3524c77a8981dc6626 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 21:14:00 +0100 Subject: [PATCH 07/12] Remove duplicated property --- FFMpegCore/FFProbe/FFProbeAnalysis.cs | 3 --- FFMpegCore/FFProbe/MediaAnalysis.cs | 1 - 2 files changed, 4 deletions(-) diff --git a/FFMpegCore/FFProbe/FFProbeAnalysis.cs b/FFMpegCore/FFProbe/FFProbeAnalysis.cs index 9967508..2177307 100644 --- a/FFMpegCore/FFProbe/FFProbeAnalysis.cs +++ b/FFMpegCore/FFProbe/FFProbeAnalysis.cs @@ -64,9 +64,6 @@ public class FFProbeStream : ITagsContainer, IDispositionContainer [JsonPropertyName("r_frame_rate")] public string FrameRate { get; set; } = null!; - - [JsonPropertyName("avg_frame_rate")] - public string AverageFrameRate { get; set; } = null!; [JsonPropertyName("pix_fmt")] public string PixelFormat { get; set; } = null!; diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs index 42cc5e5..3ecdacd 100644 --- a/FFMpegCore/FFProbe/MediaAnalysis.cs +++ b/FFMpegCore/FFProbe/MediaAnalysis.cs @@ -61,7 +61,6 @@ private VideoStream ParseVideoStream(FFProbeStream stream) DisplayAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.DisplayAspectRatio, ':'), Duration = MediaAnalysisUtils.ParseDuration(stream), FrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.FrameRate, '/')), - AverageFrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.AverageFrameRate, '/')), Height = stream.Height ?? 0, Width = stream.Width ?? 0, Profile = stream.Profile, From 1c851dc3ff7085d6c09f94f477ed5b05e1539835 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 21:15:28 +0100 Subject: [PATCH 08/12] Handle null dictionaries --- FFMpegCore/FFProbe/MediaAnalysis.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs index 3ecdacd..b5f9c34 100644 --- a/FFMpegCore/FFProbe/MediaAnalysis.cs +++ b/FFMpegCore/FFProbe/MediaAnalysis.cs @@ -114,9 +114,9 @@ public static class MediaAnalysisUtils { private static readonly Regex DurationRegex = new Regex(@"^(\d+):(\d{1,2}):(\d{1,2})\.(\d{1,3})", RegexOptions.Compiled); - internal static Dictionary ToCaseInsensitive(this Dictionary dictionary) + internal static Dictionary? ToCaseInsensitive(this Dictionary? dictionary) { - return dictionary.ToDictionary(tag => tag.Key, tag => tag.Value, StringComparer.OrdinalIgnoreCase); + return dictionary?.ToDictionary(tag => tag.Key, tag => tag.Value, StringComparer.OrdinalIgnoreCase) ?? new Dictionary(); } public static double DivideRatio((double, double) ratio) => ratio.Item1 / ratio.Item2; From 5dcbcfeaaf46b190c9ebafa9b121e11a757e426b Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 21:19:27 +0100 Subject: [PATCH 09/12] Use .NET 6 in pipelines --- .github/workflows/ci.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6946920..a68bbc6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: - name: Prepare .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.x' + dotnet-version: '6.0.x' - name: Prepare FFMpeg uses: FedericoCarboni/setup-ffmpeg@v1 - name: Test with dotnet diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5ef0a4c..7cf1425 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: - name: Prepare .NET uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.x' + dotnet-version: '6.0.x' - name: Build solution run: dotnet build --output build -c Release - name: Publish NuGet package From b33f9a3c4b7e0a21f3125aa9137c0926cb717a25 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 21:22:56 +0100 Subject: [PATCH 10/12] Bump .NET version in Test and Examples projects --- FFMpegCore.Examples/FFMpegCore.Examples.csproj | 2 +- FFMpegCore.Test/FFMpegCore.Test.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/FFMpegCore.Examples/FFMpegCore.Examples.csproj b/FFMpegCore.Examples/FFMpegCore.Examples.csproj index f9daae7..68e7b5c 100644 --- a/FFMpegCore.Examples/FFMpegCore.Examples.csproj +++ b/FFMpegCore.Examples/FFMpegCore.Examples.csproj @@ -2,7 +2,7 @@ Exe - net5.0 + net6.0 diff --git a/FFMpegCore.Test/FFMpegCore.Test.csproj b/FFMpegCore.Test/FFMpegCore.Test.csproj index 5d49065..d281c3d 100644 --- a/FFMpegCore.Test/FFMpegCore.Test.csproj +++ b/FFMpegCore.Test/FFMpegCore.Test.csproj @@ -1,7 +1,7 @@  - net5.0 + net6.0 false From 54c97296375ed0fb6ba00d9e78c5d269a77f0000 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 21:27:16 +0100 Subject: [PATCH 11/12] Add path filter to CI workflow file --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a68bbc6..b3279fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,10 +4,16 @@ on: push: branches: - master + paths: + - FFMpegCore/** + - FFMpegCore.Test/** pull_request: branches: - master - release + paths: + - FFMpegCore/** + - FFMpegCore.Test/** jobs: ci: From 37ecbb8d875d65907b455c40aa5dca9601e4f317 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Thu, 24 Mar 2022 21:28:55 +0100 Subject: [PATCH 12/12] Add ci.yml to paths in CI workflow file --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3279fd..5afb8d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -5,6 +5,7 @@ on: branches: - master paths: + - .github/workflows/ci.yml - FFMpegCore/** - FFMpegCore.Test/** pull_request: @@ -12,6 +13,7 @@ on: - master - release paths: + - .github/workflows/ci.yml - FFMpegCore/** - FFMpegCore.Test/**