Merge pull request #306 from rosenbjerg/bugfix/fixes

Bugfixes and improvements
This commit is contained in:
Malte Rosenbjerg 2022-03-25 08:24:11 +01:00 committed by GitHub
commit aa6d4827fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 109 additions and 87 deletions

View file

@ -4,10 +4,18 @@ on:
push: push:
branches: branches:
- master - master
paths:
- .github/workflows/ci.yml
- FFMpegCore/**
- FFMpegCore.Test/**
pull_request: pull_request:
branches: branches:
- master - master
- release - release
paths:
- .github/workflows/ci.yml
- FFMpegCore/**
- FFMpegCore.Test/**
jobs: jobs:
ci: ci:
@ -22,7 +30,7 @@ jobs:
- name: Prepare .NET - name: Prepare .NET
uses: actions/setup-dotnet@v1 uses: actions/setup-dotnet@v1
with: with:
dotnet-version: '5.0.x' dotnet-version: '6.0.x'
- name: Prepare FFMpeg - name: Prepare FFMpeg
uses: FedericoCarboni/setup-ffmpeg@v1 uses: FedericoCarboni/setup-ffmpeg@v1
- name: Test with dotnet - name: Test with dotnet

View file

@ -12,7 +12,7 @@ jobs:
- name: Prepare .NET - name: Prepare .NET
uses: actions/setup-dotnet@v1 uses: actions/setup-dotnet@v1
with: with:
dotnet-version: '5.0.x' dotnet-version: '6.0.x'
- name: Build solution - name: Build solution
run: dotnet build --output build -c Release run: dotnet build --output build -c Release
- name: Publish NuGet package - name: Publish NuGet package

View file

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net5.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>

View file

@ -247,7 +247,10 @@ public static bool Convert(
public static bool PosterWithAudio(string image, string audio, string output) public static bool PosterWithAudio(string image, string audio, string output)
{ {
FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4); FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4);
FFMpegHelper.ConversionSizeExceptionCheck(Image.FromFile(image)); using (var imageFile = Image.FromFile(image))
{
FFMpegHelper.ConversionSizeExceptionCheck(imageFile);
}
return FFMpegArguments return FFMpegArguments
.FromFileInput(image, false, options => options .FromFileInput(image, false, options => options

View file

@ -2,9 +2,9 @@
{ {
public class AudioStream : MediaStream public class AudioStream : MediaStream
{ {
public int Channels { get; internal set; } public int Channels { get; set; }
public string ChannelLayout { get; internal set; } = null!; public string ChannelLayout { get; set; } = null!;
public int SampleRateHz { get; internal set; } public int SampleRateHz { get; set; }
public string Profile { get; internal set; } = null!; public string Profile { get; set; } = null!;
} }
} }

View file

@ -2,6 +2,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Text.Json; using System.Text.Json;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using FFMpegCore.Arguments; using FFMpegCore.Arguments;
using FFMpegCore.Exceptions; using FFMpegCore.Exceptions;
@ -15,38 +16,33 @@ public static class FFProbe
{ {
public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null) public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var processArguments = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = processArguments.StartAndWaitForExit(); var result = processArguments.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
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));
return ParseOutput(result); return ParseOutput(result);
} }
public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null) public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = instance.StartAndWaitForExit(); var result = instance.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
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));
return ParseFramesOutput(result); return ParseFramesOutput(result);
} }
public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null) public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = instance.StartAndWaitForExit(); var result = instance.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
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));
return ParsePacketsOutput(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 instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current);
var result = instance.StartAndWaitForExit(); var result = instance.StartAndWaitForExit();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
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));
return ParseOutput(result); return ParseOutput(result);
} }
@ -78,64 +73,59 @@ public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null)
pipeArgument.Post(); pipeArgument.Post();
} }
var result = task.ConfigureAwait(false).GetAwaiter().GetResult(); var result = task.ConfigureAwait(false).GetAwaiter().GetResult();
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
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));
return ParseOutput(result); return ParseOutput(result);
} }
public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, FFOptions? ffOptions = null)
public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current);
var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
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));
return ParseOutput(result); return ParseOutput(result);
} }
public static async Task<FFProbeFrames> GetFramesAsync(string filePath, FFOptions? ffOptions = null) public static async Task<FFProbeFrames> GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); 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); return ParseFramesOutput(result);
} }
public static async Task<FFProbePackets> GetPacketsAsync(string filePath, FFOptions? ffOptions = null) public static async Task<FFProbePackets> GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
if (!File.Exists(filePath)) ThrowIfInputFileDoesNotExist(filePath);
throw new FFMpegException(FFMpegExceptionType.File, $"No file found at '{filePath}'");
var instance = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current); 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); return ParsePacketsOutput(result);
} }
public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, FFOptions? ffOptions = null) public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current);
var result = await instance.StartAndWaitForExitAsync().ConfigureAwait(false); var result = await instance.StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(false);
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
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));
return ParseOutput(result); return ParseOutput(result);
} }
public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions? ffOptions = null) public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions? ffOptions = null, CancellationToken cancellationToken = default)
{ {
var streamPipeSource = new StreamPipeSource(stream); var streamPipeSource = new StreamPipeSource(stream);
var pipeArgument = new InputPipeArgument(streamPipeSource); var pipeArgument = new InputPipeArgument(streamPipeSource);
var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current); var instance = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current);
pipeArgument.Pre(); pipeArgument.Pre();
var task = instance.StartAndWaitForExitAsync(); var task = instance.StartAndWaitForExitAsync(cancellationToken);
try try
{ {
await pipeArgument.During().ConfigureAwait(false); await pipeArgument.During(cancellationToken).ConfigureAwait(false);
} }
catch(IOException) catch(IOException)
{ {
@ -145,8 +135,7 @@ public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions?
pipeArgument.Post(); pipeArgument.Post();
} }
var result = await task.ConfigureAwait(false); var result = await task.ConfigureAwait(false);
if (result.ExitCode != 0) ThrowIfExitCodeNotZero(result);
throw new FFProbeProcessException($"ffprobe exited with non-zero exit-code ({result.ExitCode} - {string.Join("\n", result.ErrorData)})", result.ErrorData);
pipeArgument.Post(); pipeArgument.Post();
return ParseOutput(result); return ParseOutput(result);
@ -174,7 +163,7 @@ private static FFProbeFrames ParseFramesOutput(IProcessResult instance)
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString
}) ; }) ;
return ffprobeAnalysis; return ffprobeAnalysis!;
} }
private static FFProbePackets ParsePacketsOutput(IProcessResult instance) private static FFProbePackets ParsePacketsOutput(IProcessResult instance)
@ -186,9 +175,25 @@ private static FFProbePackets ParsePacketsOutput(IProcessResult instance)
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString | System.Text.Json.Serialization.JsonNumberHandling.WriteAsString
}) ; }) ;
return ffprobeAnalysis; 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) private static ProcessArguments PrepareStreamAnalysisInstance(string filePath, FFOptions ffOptions)
=> PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"", ffOptions); => PrepareInstance($"-loglevel error -print_format json -show_format -sexagesimal -show_streams \"{filePath}\"", ffOptions);

View file

@ -6,7 +6,7 @@ namespace FFMpegCore
public class FFProbeFrameAnalysis public class FFProbeFrameAnalysis
{ {
[JsonPropertyName("media_type")] [JsonPropertyName("media_type")]
public string MediaType { get; set; } public string MediaType { get; set; } = null!;
[JsonPropertyName("stream_index")] [JsonPropertyName("stream_index")]
public int StreamIndex { get; set; } public int StreamIndex { get; set; }
@ -18,25 +18,25 @@ public class FFProbeFrameAnalysis
public long PacketPts { get; set; } public long PacketPts { get; set; }
[JsonPropertyName("pkt_pts_time")] [JsonPropertyName("pkt_pts_time")]
public string PacketPtsTime { get; set; } public string PacketPtsTime { get; set; } = null!;
[JsonPropertyName("pkt_dts")] [JsonPropertyName("pkt_dts")]
public long PacketDts { get; set; } public long PacketDts { get; set; }
[JsonPropertyName("pkt_dts_time")] [JsonPropertyName("pkt_dts_time")]
public string PacketDtsTime { get; set; } public string PacketDtsTime { get; set; } = null!;
[JsonPropertyName("best_effort_timestamp")] [JsonPropertyName("best_effort_timestamp")]
public long BestEffortTimestamp { get; set; } public long BestEffortTimestamp { get; set; }
[JsonPropertyName("best_effort_timestamp_time")] [JsonPropertyName("best_effort_timestamp_time")]
public string BestEffortTimestampTime { get; set; } public string BestEffortTimestampTime { get; set; } = null!;
[JsonPropertyName("pkt_duration")] [JsonPropertyName("pkt_duration")]
public int PacketDuration { get; set; } public int PacketDuration { get; set; }
[JsonPropertyName("pkt_duration_time")] [JsonPropertyName("pkt_duration_time")]
public string PacketDurationTime { get; set; } public string PacketDurationTime { get; set; } = null!;
[JsonPropertyName("pkt_pos")] [JsonPropertyName("pkt_pos")]
public long PacketPos { get; set; } public long PacketPos { get; set; }
@ -51,10 +51,10 @@ public class FFProbeFrameAnalysis
public long Height { get; set; } public long Height { get; set; }
[JsonPropertyName("pix_fmt")] [JsonPropertyName("pix_fmt")]
public string PixelFormat { get; set; } public string PixelFormat { get; set; } = null!;
[JsonPropertyName("pict_type")] [JsonPropertyName("pict_type")]
public string PictureType { get; set; } public string PictureType { get; set; } = null!;
[JsonPropertyName("coded_picture_number")] [JsonPropertyName("coded_picture_number")]
public long CodedPictureNumber { get; set; } public long CodedPictureNumber { get; set; }
@ -72,12 +72,12 @@ public class FFProbeFrameAnalysis
public int RepeatPicture { get; set; } public int RepeatPicture { get; set; }
[JsonPropertyName("chroma_location")] [JsonPropertyName("chroma_location")]
public string ChromaLocation { get; set; } public string ChromaLocation { get; set; } = null!;
} }
public class FFProbeFrames public class FFProbeFrames
{ {
[JsonPropertyName("frames")] [JsonPropertyName("frames")]
public List<FFProbeFrameAnalysis> Frames { get; set; } public List<FFProbeFrameAnalysis> Frames { get; set; } = null!;
} }
} }

View file

@ -25,7 +25,7 @@ private MediaFormat ParseFormat(Format analysisFormat)
StreamCount = analysisFormat.NbStreams, StreamCount = analysisFormat.NbStreams,
ProbeScore = analysisFormat.ProbeScore, ProbeScore = analysisFormat.ProbeScore,
BitRate = long.Parse(analysisFormat.BitRate ?? "0"), BitRate = long.Parse(analysisFormat.BitRate ?? "0"),
Tags = analysisFormat.Tags, Tags = analysisFormat.Tags.ToCaseInsensitive(),
}; };
} }
@ -68,7 +68,7 @@ private VideoStream ParseVideoStream(FFProbeStream stream)
Rotation = (int)float.Parse(stream.GetRotate() ?? "0"), Rotation = (int)float.Parse(stream.GetRotate() ?? "0"),
Language = stream.GetLanguage(), Language = stream.GetLanguage(),
Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition), Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition),
Tags = stream.Tags, Tags = stream.Tags.ToCaseInsensitive(),
}; };
} }
@ -89,7 +89,7 @@ private AudioStream ParseAudioStream(FFProbeStream stream)
Profile = stream.Profile, Profile = stream.Profile,
Language = stream.GetLanguage(), Language = stream.GetLanguage(),
Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition), Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition),
Tags = stream.Tags, Tags = stream.Tags.ToCaseInsensitive(),
}; };
} }
@ -104,15 +104,20 @@ private SubtitleStream ParseSubtitleStream(FFProbeStream stream)
Duration = MediaAnalysisUtils.ParseDuration(stream), Duration = MediaAnalysisUtils.ParseDuration(stream),
Language = stream.GetLanguage(), Language = stream.GetLanguage(),
Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition), Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition),
Tags = stream.Tags, Tags = stream.Tags.ToCaseInsensitive(),
}; };
} }
} }
public static class MediaAnalysisUtils public static class MediaAnalysisUtils
{ {
private static readonly Regex DurationRegex = new Regex(@"^(\d+):(\d{1,2}):(\d{1,2})\.(\d{1,3})", RegexOptions.Compiled); private static readonly Regex DurationRegex = new Regex(@"^(\d+):(\d{1,2}):(\d{1,2})\.(\d{1,3})", RegexOptions.Compiled);
internal static Dictionary<string, string>? ToCaseInsensitive(this Dictionary<string, string>? dictionary)
{
return dictionary?.ToDictionary(tag => tag.Key, tag => tag.Value, StringComparer.OrdinalIgnoreCase) ?? new Dictionary<string, string>();
}
public static double DivideRatio((double, double) ratio) => ratio.Item1 / ratio.Item2; public static double DivideRatio((double, double) ratio) => ratio.Item1 / ratio.Item2;
public static (int, int) ParseRatioInt(string input, char separator) public static (int, int) ParseRatioInt(string input, char separator)
@ -183,7 +188,7 @@ public static TimeSpan ParseDuration(FFProbeStream ffProbeStream)
return null; return null;
} }
var result = new Dictionary<string, bool>(disposition.Count); var result = new Dictionary<string, bool>(disposition.Count, StringComparer.Ordinal);
foreach (var pair in disposition) foreach (var pair in disposition)
{ {

View file

@ -5,18 +5,18 @@
namespace FFMpegCore namespace FFMpegCore
{ {
public class MediaStream public abstract class MediaStream
{ {
public int Index { get; internal set; } public int Index { get; set; }
public string CodecName { get; internal set; } = null!; public string CodecName { get; set; } = null!;
public string CodecLongName { get; internal set; } = null!; public string CodecLongName { get; set; } = null!;
public string CodecTagString { get; set; } = null!; public string CodecTagString { get; set; } = null!;
public string CodecTag { get; set; } = null!; public string CodecTag { get; set; } = null!;
public long BitRate { get; internal set; } public long BitRate { get; set; }
public TimeSpan Duration { get; internal set; } public TimeSpan Duration { get; set; }
public string? Language { get; internal set; } public string? Language { get; set; }
public Dictionary<string, bool>? Disposition { get; internal set; } public Dictionary<string, bool>? Disposition { get; set; }
public Dictionary<string, string>? Tags { get; internal set; } public Dictionary<string, string>? Tags { get; set; }
public Codec GetCodecInfo() => FFMpeg.GetCodec(CodecName); public Codec GetCodecInfo() => FFMpeg.GetCodec(CodecName);
} }

View file

@ -6,7 +6,7 @@ namespace FFMpegCore
public class FFProbePacketAnalysis public class FFProbePacketAnalysis
{ {
[JsonPropertyName("codec_type")] [JsonPropertyName("codec_type")]
public string CodecType { get; set; } public string CodecType { get; set; } = null!;
[JsonPropertyName("stream_index")] [JsonPropertyName("stream_index")]
public int StreamIndex { get; set; } public int StreamIndex { get; set; }
@ -15,19 +15,19 @@ public class FFProbePacketAnalysis
public long Pts { get; set; } public long Pts { get; set; }
[JsonPropertyName("pts_time")] [JsonPropertyName("pts_time")]
public string PtsTime { get; set; } public string PtsTime { get; set; } = null!;
[JsonPropertyName("dts")] [JsonPropertyName("dts")]
public long Dts { get; set; } public long Dts { get; set; }
[JsonPropertyName("dts_time")] [JsonPropertyName("dts_time")]
public string DtsTime { get; set; } public string DtsTime { get; set; } = null!;
[JsonPropertyName("duration")] [JsonPropertyName("duration")]
public int Duration { get; set; } public int Duration { get; set; }
[JsonPropertyName("duration_time")] [JsonPropertyName("duration_time")]
public string DurationTime { get; set; } public string DurationTime { get; set; } = null!;
[JsonPropertyName("size")] [JsonPropertyName("size")]
public int Size { get; set; } public int Size { get; set; }
@ -36,12 +36,12 @@ public class FFProbePacketAnalysis
public long Pos { get; set; } public long Pos { get; set; }
[JsonPropertyName("flags")] [JsonPropertyName("flags")]
public string Flags { get; set; } public string Flags { get; set; } = null!;
} }
public class FFProbePackets public class FFProbePackets
{ {
[JsonPropertyName("packets")] [JsonPropertyName("packets")]
public List<FFProbePacketAnalysis> Packets { get; set; } public List<FFProbePacketAnalysis> Packets { get; set; } = null!;
} }
} }

View file

@ -4,15 +4,16 @@ namespace FFMpegCore
{ {
public class VideoStream : MediaStream public class VideoStream : MediaStream
{ {
public double AvgFrameRate { get; internal set; } public double AvgFrameRate { get; set; }
public int BitsPerRawSample { get; internal set; } public int BitsPerRawSample { get; set; }
public (int Width, int Height) DisplayAspectRatio { get; internal set; } public (int Width, int Height) DisplayAspectRatio { get; set; }
public string Profile { get; internal set; } = null!; public string Profile { get; set; } = null!;
public int Width { get; internal set; } public int Width { get; set; }
public int Height { get; internal set; } public int Height { get; set; }
public double FrameRate { get; internal set; } public double FrameRate { get; set; }
public string PixelFormat { get; internal set; } = null!; public string PixelFormat { get; set; } = null!;
public int Rotation { get; set; } public int Rotation { get; set; }
public double AverageFrameRate { get; set; }
public PixelFormat GetPixelFormatInfo() => FFMpeg.GetPixelFormat(PixelFormat); public PixelFormat GetPixelFormatInfo() => FFMpeg.GetPixelFormat(PixelFormat);
} }