From 152683323e3bdcd3f7365d5f31667dba2a3804e3 Mon Sep 17 00:00:00 2001 From: Malte Rosenbjerg Date: Tue, 12 May 2020 21:05:00 +0200 Subject: [PATCH] Cleanup Former-commit-id: d95f687e46eda15a7d8df084256d09f24fcc29ca --- FFMpegCore.Test/ArgumentBuilderTest.cs | 3 +- FFMpegCore.Test/AudioTest.cs | 2 +- FFMpegCore.Test/FFProbeTests.cs | 2 +- FFMpegCore.Test/PixelFormatTests.cs | 17 +- FFMpegCore.Test/Resources/VideoLibrary.cs | 5 +- FFMpegCore.Test/VideoTest.cs | 34 ++-- .../FFMpeg/Arguments/AudioCodecArgument.cs | 2 +- .../Arguments/DisableChannelArgument.cs | 2 +- .../FFMpeg/Arguments/ForceFormatArgument.cs | 2 +- .../FFMpeg/Arguments/ForcePixelFormat.cs | 2 +- FFMpegCore/FFMpeg/Arguments/InputArgument.cs | 2 +- FFMpegCore/FFMpeg/Arguments/OutputArgument.cs | 8 +- FFMpegCore/FFMpeg/Arguments/PipeArgument.cs | 5 +- .../FFMpeg/Arguments/VideoCodecArgument.cs | 2 +- FFMpegCore/FFMpeg/Enums/Channel.cs | 9 + FFMpegCore/FFMpeg/Enums/CodecType.cs | 14 ++ FFMpegCore/FFMpeg/Enums/Enums.cs | 54 ----- FFMpegCore/FFMpeg/Enums/FeatureStatus.cs | 9 + FFMpegCore/FFMpeg/Enums/Filter.cs | 8 + FFMpegCore/FFMpeg/FFMpeg.cs | 176 +--------------- FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs | 2 +- FFMpegCore/FFMpeg/FFMpegArguments.cs | 7 +- FFMpegCore/FFMpeg/FFMpegCache.cs | 10 +- FFMpegCore/FFMpeg/FFMpegUtils.cs | 189 ++++++++++++++++++ FFMpegCore/FFMpeg/{Enums => Models}/Codec.cs | 44 ++-- .../{Enums => Models}/ContainerFormat.cs | 7 +- .../{Exceptions => Models}/FFMpegException.cs | 2 +- .../FFMpeg/{Enums => Models}/PixelFormat.cs | 11 +- .../FFMpeg/Pipes/RawVideoPipeDataWriter.cs | 2 +- FFMpegCore/FFMpeg/Utils/AudioCodec.cs | 14 ++ .../FFMpeg/{Enums => Utils}/FileExtension.cs | 3 +- FFMpegCore/FFMpeg/Utils/VideoCodec.cs | 13 ++ FFMpegCore/FFMpeg/Utils/VideoType.cs | 15 ++ FFMpegCore/FFMpegCore.csproj | 4 - FFMpegCore/FFProbe/FFProbe.cs | 12 +- FFMpegCore/FFProbe/FFProbeAnalysis.cs | 63 ------ FFMpegCore/FFProbe/MediaAnalysis.cs | 24 ++- .../FFProbe/{ => Models}/AudioStream.cs | 0 FFMpegCore/FFProbe/Models/MediaStream.cs | 12 ++ .../SimpleStream.cs} | 9 +- FFMpegCore/FFProbe/Models/TextStream.cs | 7 + .../FFProbe/{ => Models}/VideoStream.cs | 4 +- FFMpegCore/FFProbe/Stream.cs | 64 ++++++ FFMpegCore/FFProbe/Tags.cs | 13 ++ FFMpegCore/Helpers/FFMpegHelper.cs | 2 +- FFMpegCore/Helpers/FFProbeHelper.cs | 2 +- FFMpegCore/ImageInfo.cs | 2 +- 47 files changed, 485 insertions(+), 410 deletions(-) create mode 100644 FFMpegCore/FFMpeg/Enums/Channel.cs create mode 100644 FFMpegCore/FFMpeg/Enums/CodecType.cs delete mode 100644 FFMpegCore/FFMpeg/Enums/Enums.cs create mode 100644 FFMpegCore/FFMpeg/Enums/FeatureStatus.cs create mode 100644 FFMpegCore/FFMpeg/Enums/Filter.cs create mode 100644 FFMpegCore/FFMpeg/FFMpegUtils.cs rename FFMpegCore/FFMpeg/{Enums => Models}/Codec.cs (82%) rename FFMpegCore/FFMpeg/{Enums => Models}/ContainerFormat.cs (90%) rename FFMpegCore/FFMpeg/{Exceptions => Models}/FFMpegException.cs (94%) rename FFMpegCore/FFMpeg/{Enums => Models}/PixelFormat.cs (84%) create mode 100644 FFMpegCore/FFMpeg/Utils/AudioCodec.cs rename FFMpegCore/FFMpeg/{Enums => Utils}/FileExtension.cs (93%) create mode 100644 FFMpegCore/FFMpeg/Utils/VideoCodec.cs create mode 100644 FFMpegCore/FFMpeg/Utils/VideoType.cs rename FFMpegCore/FFProbe/{ => Models}/AudioStream.cs (100%) create mode 100644 FFMpegCore/FFProbe/Models/MediaStream.cs rename FFMpegCore/FFProbe/{MediaStream.cs => Models/SimpleStream.cs} (59%) create mode 100644 FFMpegCore/FFProbe/Models/TextStream.cs rename FFMpegCore/FFProbe/{ => Models}/VideoStream.cs (82%) create mode 100644 FFMpegCore/FFProbe/Stream.cs create mode 100644 FFMpegCore/FFProbe/Tags.cs diff --git a/FFMpegCore.Test/ArgumentBuilderTest.cs b/FFMpegCore.Test/ArgumentBuilderTest.cs index 6667624..943d7a6 100644 --- a/FFMpegCore.Test/ArgumentBuilderTest.cs +++ b/FFMpegCore.Test/ArgumentBuilderTest.cs @@ -2,7 +2,8 @@ using System; using FFMpegCore.Arguments; using FFMpegCore.Enums; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; +using FFMpegCore.Utils; namespace FFMpegCore.Test { diff --git a/FFMpegCore.Test/AudioTest.cs b/FFMpegCore.Test/AudioTest.cs index 552ca24..8ebf03b 100644 --- a/FFMpegCore.Test/AudioTest.cs +++ b/FFMpegCore.Test/AudioTest.cs @@ -1,8 +1,8 @@ using System; -using FFMpegCore.Enums; using FFMpegCore.Test.Resources; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.IO; +using FFMpegCore.Utils; namespace FFMpegCore.Test { diff --git a/FFMpegCore.Test/FFProbeTests.cs b/FFMpegCore.Test/FFProbeTests.cs index 558f29c..74aef63 100644 --- a/FFMpegCore.Test/FFProbeTests.cs +++ b/FFMpegCore.Test/FFProbeTests.cs @@ -49,7 +49,7 @@ public async Task Probe_Async_Success() var info = await FFProbe.AnalyseAsync(VideoLibrary.LocalVideo.FullName); Assert.AreEqual(13, info.Duration.Seconds); } - + [TestMethod, Timeout(10000)] public void Probe_Success_FromStream() { diff --git a/FFMpegCore.Test/PixelFormatTests.cs b/FFMpegCore.Test/PixelFormatTests.cs index 3e7e841..f1d98c0 100644 --- a/FFMpegCore.Test/PixelFormatTests.cs +++ b/FFMpegCore.Test/PixelFormatTests.cs @@ -1,8 +1,5 @@ -using FFMpegCore.Exceptions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using FFMpegCore.Models; namespace FFMpegCore.Test { @@ -12,33 +9,33 @@ public class PixelFormatTests [TestMethod] public void PixelFormats_Enumerate() { - var formats = FFMpeg.GetPixelFormats(); + var formats = FFMpegUtils.GetPixelFormats(); Assert.IsTrue(formats.Count > 0); } [TestMethod] public void PixelFormats_TryGetExisting() { - Assert.IsTrue(FFMpeg.TryGetPixelFormat("yuv420p", out _)); + Assert.IsTrue(FFMpegUtils.TryGetPixelFormat("yuv420p", out _)); } [TestMethod] public void PixelFormats_TryGetNotExisting() { - Assert.IsFalse(FFMpeg.TryGetPixelFormat("yuv420pppUnknown", out _)); + Assert.IsFalse(FFMpegUtils.TryGetPixelFormat("yuv420pppUnknown", out _)); } [TestMethod] public void PixelFormats_GetExisting() { - var fmt = FFMpeg.GetPixelFormat("yuv420p"); + var fmt = FFMpegUtils.GetPixelFormat("yuv420p"); Assert.IsTrue(fmt.Components == 3 && fmt.BitsPerPixel == 12); } [TestMethod] public void PixelFormats_GetNotExisting() { - Assert.ThrowsException(() => FFMpeg.GetPixelFormat("yuv420pppUnknown")); + Assert.ThrowsException(() => FFMpegUtils.GetPixelFormat("yuv420pppUnknown")); } } } diff --git a/FFMpegCore.Test/Resources/VideoLibrary.cs b/FFMpegCore.Test/Resources/VideoLibrary.cs index 3b0c4e0..d25e107 100644 --- a/FFMpegCore.Test/Resources/VideoLibrary.cs +++ b/FFMpegCore.Test/Resources/VideoLibrary.cs @@ -1,6 +1,5 @@ -using System; -using System.IO; -using FFMpegCore.Enums; +using System.IO; +using FFMpegCore.Models; namespace FFMpegCore.Test.Resources { diff --git a/FFMpegCore.Test/VideoTest.cs b/FFMpegCore.Test/VideoTest.cs index ffa5da3..645e3bf 100644 --- a/FFMpegCore.Test/VideoTest.cs +++ b/FFMpegCore.Test/VideoTest.cs @@ -7,8 +7,9 @@ using System.IO; using System.Linq; using FFMpegCore.Arguments; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; using FFMpegCore.Pipes; +using FFMpegCore.Utils; namespace FFMpegCore.Test { @@ -127,7 +128,8 @@ private void ConvertToStreamPipe(params IArgument[] inputArguments) var scaling = arguments.Find(); - processor.ProcessSynchronously(); + var result = processor.ProcessSynchronously(); + Assert.IsTrue(result); ms.Position = 0; var outputVideo = FFProbe.Analyse(ms); @@ -157,7 +159,7 @@ private void ConvertToStreamPipe(params IArgument[] inputArguments) } } - public void Convert(ContainerFormat type, Action validationMethod, params IArgument[] inputArguments) + private void Convert(ContainerFormat type, Action validationMethod, params IArgument[] inputArguments) { var output = Input.OutputLocation(type); @@ -206,13 +208,8 @@ public void Convert(ContainerFormat type, Action validationMethod File.Delete(output); } } - - public void Convert(ContainerFormat type, params IArgument[] inputArguments) - { - Convert(type, null, inputArguments); - } - - public void ConvertFromPipe(ContainerFormat type, System.Drawing.Imaging.PixelFormat fmt, params IArgument[] inputArguments) + + private void ConvertFromPipe(ContainerFormat type, System.Drawing.Imaging.PixelFormat fmt, params IArgument[] inputArguments) { var output = Input.OutputLocation(type); @@ -276,7 +273,7 @@ public void Video_ToMP4_YUV444p() [TestMethod] public void Video_ToMP4_Args() { - Convert(VideoType.Mp4, new VideoCodecArgument(VideoCodec.LibX264)); + Convert(VideoType.Mp4, null, new VideoCodecArgument(VideoCodec.LibX264)); } [DataTestMethod] @@ -321,13 +318,14 @@ public void Video_ToMP4_Args_StreamOutputPipe_Async() { using var ms = new MemoryStream(); var pipeSource = new StreamPipeDataReader(ms); - FFMpegArguments + var result = FFMpegArguments .FromInputFiles(VideoLibrary.LocalVideo) .WithVideoCodec(VideoCodec.LibX264) .ForceFormat("matroska") .OutputToPipe(pipeSource) .ProcessAsynchronously() .WaitForResult(); + Assert.IsTrue(result); } [TestMethod] @@ -345,7 +343,7 @@ public void Video_ToTS() [TestMethod] public void Video_ToTS_Args() { - Convert(VideoType.Ts, + Convert(VideoType.Ts, null, new CopyArgument(), new BitStreamFilterArgument(Channel.Video, Filter.H264_Mp4ToAnnexB), new ForceFormatArgument(VideoType.MpegTs)); @@ -369,7 +367,7 @@ public void Video_ToOGV_Resize() [TestMethod] public void Video_ToOGV_Resize_Args() { - Convert(VideoType.Ogv, new ScaleArgument(VideoSize.Ed), new VideoCodecArgument(VideoCodec.LibTheora)); + Convert(VideoType.Ogv, null, new ScaleArgument(VideoSize.Ed), new VideoCodecArgument(VideoCodec.LibTheora)); } [DataTestMethod] @@ -390,7 +388,7 @@ public void Video_ToMP4_Resize() [TestMethod] public void Video_ToMP4_Resize_Args() { - Convert(VideoType.Mp4, new ScaleArgument(VideoSize.Ld), new VideoCodecArgument(VideoCodec.LibX264)); + Convert(VideoType.Mp4, null, new ScaleArgument(VideoSize.Ld), new VideoCodecArgument(VideoCodec.LibX264)); } [DataTestMethod] @@ -547,7 +545,6 @@ public void Video_With_Only_Audio_Should_Extract_Metadata() Assert.AreEqual(null, video.PrimaryVideoStream); Assert.AreEqual("aac", video.PrimaryAudioStream.CodecName); Assert.AreEqual(79.5, video.Duration.TotalSeconds, 0.5); - // Assert.AreEqual(1.25, video.Size); } [TestMethod] @@ -621,13 +618,14 @@ public void Video_TranscodeInMemory() var reader = new StreamPipeDataReader(resStream); var writer = new RawVideoPipeDataWriter(BitmapSource.CreateBitmaps(128, System.Drawing.Imaging.PixelFormat.Format24bppRgb, 128, 128)); - FFMpegArguments + var result = FFMpegArguments .FromPipe(writer) .WithVideoCodec("vp9") .ForceFormat("webm") .OutputToPipe(reader) .ProcessSynchronously(); - + Assert.IsTrue(result); + resStream.Position = 0; var vi = FFProbe.Analyse(resStream); Assert.AreEqual(vi.PrimaryVideoStream.Width, 128); diff --git a/FFMpegCore/FFMpeg/Arguments/AudioCodecArgument.cs b/FFMpegCore/FFMpeg/Arguments/AudioCodecArgument.cs index 273bb02..4d3102a 100644 --- a/FFMpegCore/FFMpeg/Arguments/AudioCodecArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/AudioCodecArgument.cs @@ -1,5 +1,5 @@ using FFMpegCore.Enums; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; namespace FFMpegCore.Arguments { diff --git a/FFMpegCore/FFMpeg/Arguments/DisableChannelArgument.cs b/FFMpegCore/FFMpeg/Arguments/DisableChannelArgument.cs index d683775..98c01b7 100644 --- a/FFMpegCore/FFMpeg/Arguments/DisableChannelArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/DisableChannelArgument.cs @@ -1,5 +1,5 @@ using FFMpegCore.Enums; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; namespace FFMpegCore.Arguments { diff --git a/FFMpegCore/FFMpeg/Arguments/ForceFormatArgument.cs b/FFMpegCore/FFMpeg/Arguments/ForceFormatArgument.cs index 9524698..fcf80cb 100644 --- a/FFMpegCore/FFMpeg/Arguments/ForceFormatArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/ForceFormatArgument.cs @@ -1,4 +1,4 @@ -using FFMpegCore.Enums; +using FFMpegCore.Models; namespace FFMpegCore.Arguments { diff --git a/FFMpegCore/FFMpeg/Arguments/ForcePixelFormat.cs b/FFMpegCore/FFMpeg/Arguments/ForcePixelFormat.cs index 7614ae3..3935c6f 100644 --- a/FFMpegCore/FFMpeg/Arguments/ForcePixelFormat.cs +++ b/FFMpegCore/FFMpeg/Arguments/ForcePixelFormat.cs @@ -1,4 +1,4 @@ -using FFMpegCore.Enums; +using FFMpegCore.Models; namespace FFMpegCore.Arguments { diff --git a/FFMpegCore/FFMpeg/Arguments/InputArgument.cs b/FFMpegCore/FFMpeg/Arguments/InputArgument.cs index c201c1f..20e7b7b 100644 --- a/FFMpegCore/FFMpeg/Arguments/InputArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/InputArgument.cs @@ -50,7 +50,7 @@ public interface IArgument public interface IInputOutputArgument : IArgument { void Pre() {} - Task During(CancellationToken? cancellationToken = null) => Task.CompletedTask; + Task During(CancellationToken cancellationToken) => Task.CompletedTask; void Post() {} } diff --git a/FFMpegCore/FFMpeg/Arguments/OutputArgument.cs b/FFMpegCore/FFMpeg/Arguments/OutputArgument.cs index 5a53886..d5b4ff6 100644 --- a/FFMpegCore/FFMpeg/Arguments/OutputArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/OutputArgument.cs @@ -1,6 +1,6 @@ using System; using System.IO; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; namespace FFMpegCore.Arguments { @@ -11,11 +11,13 @@ public class OutputArgument : IOutputArgument { public readonly string Path; public readonly bool Overwrite; + public readonly bool VerifyOutputExists; - public OutputArgument(string path, bool overwrite = false) + public OutputArgument(string path, bool overwrite = false, bool verifyOutputExists = true) { Path = path; Overwrite = overwrite; + VerifyOutputExists = verifyOutputExists; } public void Pre() @@ -25,7 +27,7 @@ public void Pre() } public void Post() { - if (!File.Exists(Path)) + if (VerifyOutputExists && !File.Exists(Path)) throw new FFMpegException(FFMpegExceptionType.File, "Output file was not created"); } diff --git a/FFMpegCore/FFMpeg/Arguments/PipeArgument.cs b/FFMpegCore/FFMpeg/Arguments/PipeArgument.cs index 77db5db..8660ab2 100644 --- a/FFMpegCore/FFMpeg/Arguments/PipeArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/PipeArgument.cs @@ -34,16 +34,15 @@ public void Post() Pipe = null!; } - public async Task During(CancellationToken? cancellationToken = null) + public async Task During(CancellationToken cancellationToken) { try { - await ProcessDataAsync(cancellationToken ?? CancellationToken.None).ConfigureAwait(false); + await ProcessDataAsync(cancellationToken).ConfigureAwait(false); } catch (TaskCanceledException) { } - Post(); } public abstract Task ProcessDataAsync(CancellationToken token); diff --git a/FFMpegCore/FFMpeg/Arguments/VideoCodecArgument.cs b/FFMpegCore/FFMpeg/Arguments/VideoCodecArgument.cs index 9386822..6b91da3 100644 --- a/FFMpegCore/FFMpeg/Arguments/VideoCodecArgument.cs +++ b/FFMpegCore/FFMpeg/Arguments/VideoCodecArgument.cs @@ -1,5 +1,5 @@ using FFMpegCore.Enums; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; namespace FFMpegCore.Arguments { diff --git a/FFMpegCore/FFMpeg/Enums/Channel.cs b/FFMpegCore/FFMpeg/Enums/Channel.cs new file mode 100644 index 0000000..51e0254 --- /dev/null +++ b/FFMpegCore/FFMpeg/Enums/Channel.cs @@ -0,0 +1,9 @@ +namespace FFMpegCore.Enums +{ + public enum Channel + { + Audio, + Video, + Both + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Enums/CodecType.cs b/FFMpegCore/FFMpeg/Enums/CodecType.cs new file mode 100644 index 0000000..3900d74 --- /dev/null +++ b/FFMpegCore/FFMpeg/Enums/CodecType.cs @@ -0,0 +1,14 @@ +using System; + +namespace FFMpegCore.Enums +{ + [Flags] + public enum CodecType + { + Unknown = 0, + Video = 1 << 1, + Audio = 1 << 2, + Subtitle = 1 << 3, + Data = 1 << 4, + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Enums/Enums.cs b/FFMpegCore/FFMpeg/Enums/Enums.cs deleted file mode 100644 index 2bbab5f..0000000 --- a/FFMpegCore/FFMpeg/Enums/Enums.cs +++ /dev/null @@ -1,54 +0,0 @@ -namespace FFMpegCore.Enums -{ - public enum CodecType - { - Unknown = 0, - Video = 1 << 1, - Audio = 1 << 2, - Subtitle = 1 << 3, - Data = 1 << 4, - } - - public static class VideoCodec - { - public static Codec LibX264 => FFMpeg.GetCodec("libx264"); - public static Codec LibVpx => FFMpeg.GetCodec("libvpx"); - public static Codec LibTheora => FFMpeg.GetCodec("libtheora"); - public static Codec Png => FFMpeg.GetCodec("png"); - public static Codec MpegTs => FFMpeg.GetCodec("mpegts"); - } - - public static class AudioCodec - { - public static Codec Aac => FFMpeg.GetCodec("aac"); - public static Codec LibVorbis => FFMpeg.GetCodec("libvorbis"); - public static Codec LibFdk_Aac => FFMpeg.GetCodec("libfdk_aac"); - public static Codec Ac3 => FFMpeg.GetCodec("ac3"); - public static Codec Eac3 => FFMpeg.GetCodec("eac3"); - public static Codec LibMp3Lame => FFMpeg.GetCodec("libmp3lame"); - } - - public static class VideoType - { - public static ContainerFormat MpegTs => FFMpeg.GetContinerFormat("mpegts"); - public static ContainerFormat Ts => FFMpeg.GetContinerFormat("mpegts"); - public static ContainerFormat Mp4 => FFMpeg.GetContinerFormat("mp4"); - public static ContainerFormat Mov => FFMpeg.GetContinerFormat("mov"); - public static ContainerFormat Avi => FFMpeg.GetContinerFormat("avi"); - public static ContainerFormat Ogv => FFMpeg.GetContinerFormat("ogv"); - public static ContainerFormat WebM => FFMpeg.GetContinerFormat("webm"); - } - - public enum Filter - { - H264_Mp4ToAnnexB, - Aac_AdtstoAsc - } - - public enum Channel - { - Audio, - Video, - Both - } -} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Enums/FeatureStatus.cs b/FFMpegCore/FFMpeg/Enums/FeatureStatus.cs new file mode 100644 index 0000000..78d2885 --- /dev/null +++ b/FFMpegCore/FFMpeg/Enums/FeatureStatus.cs @@ -0,0 +1,9 @@ +namespace FFMpegCore.Enums +{ + public enum FeatureStatus + { + Unknown, + NotSupported, + Supported, + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Enums/Filter.cs b/FFMpegCore/FFMpeg/Enums/Filter.cs new file mode 100644 index 0000000..27a9cd8 --- /dev/null +++ b/FFMpegCore/FFMpeg/Enums/Filter.cs @@ -0,0 +1,8 @@ +namespace FFMpegCore.Enums +{ + public enum Filter + { + H264_Mp4ToAnnexB, + Aac_AdtstoAsc + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/FFMpeg.cs b/FFMpegCore/FFMpeg/FFMpeg.cs index 13d141f..9a82e87 100644 --- a/FFMpegCore/FFMpeg/FFMpeg.cs +++ b/FFMpegCore/FFMpeg/FFMpeg.cs @@ -5,12 +5,13 @@ using System.IO; using System.Linq; using FFMpegCore.Enums; -using FFMpegCore.Exceptions; using FFMpegCore.Helpers; +using FFMpegCore.Models; +using FFMpegCore.Utils; namespace FFMpegCore { - public static class FFMpeg + public static partial class FFMpeg { /// /// Saves a 'png' thumbnail from the input video. @@ -324,178 +325,7 @@ public static bool ReplaceAudio(string input, string inputAudio, string output, .ProcessSynchronously(); } - #region PixelFormats - internal static IReadOnlyList GetPixelFormatsInternal() - { - FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); - var list = new List(); - using var instance = new Instances.Instance(FFMpegOptions.Options.FFmpegBinary(), "-pix_fmts"); - instance.DataReceived += (e, args) => - { - if (Enums.PixelFormat.TryParse(args.Data, out var fmt)) - list.Add(fmt); - }; - - var exitCode = instance.BlockUntilFinished(); - if (exitCode != 0) throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", instance.OutputData)); - - return list.AsReadOnly(); - } - - public static IReadOnlyList GetPixelFormats() - { - if (!FFMpegOptions.Options.UseCache) - return GetPixelFormatsInternal(); - return FFMpegCache.PixelFormats.Values.ToList().AsReadOnly(); - } - - public static bool TryGetPixelFormat(string name, out Enums.PixelFormat fmt) - { - if (!FFMpegOptions.Options.UseCache) - { - fmt = GetPixelFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim()); - return fmt != null; - } - else - return FFMpegCache.PixelFormats.TryGetValue(name, out fmt); - } - - public static Enums.PixelFormat GetPixelFormat(string name) - { - if (TryGetPixelFormat(name, out var fmt)) - return fmt; - throw new FFMpegException(FFMpegExceptionType.Operation, $"Pixel format \"{name}\" not supported"); - } - #endregion - - #region Codecs - internal static void ParsePartOfCodecs(Dictionary codecs, string arguments, Func parser) - { - FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); - - using var instance = new Instances.Instance(FFMpegOptions.Options.FFmpegBinary(), arguments); - instance.DataReceived += (e, args) => - { - var codec = parser(args.Data); - if(codec != null) - if (codecs.TryGetValue(codec.Name, out var parentCodec)) - parentCodec.Merge(codec); - else - codecs.Add(codec.Name, codec); - }; - - var exitCode = instance.BlockUntilFinished(); - if (exitCode != 0) throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", instance.OutputData)); - } - - internal static Dictionary GetCodecsInternal() - { - var res = new Dictionary(); - ParsePartOfCodecs(res, "-codecs", (s) => - { - if (Codec.TryParseFromCodecs(s, out var codec)) - return codec; - return null; - }); - ParsePartOfCodecs(res, "-encoders", (s) => - { - if (Codec.TryParseFromEncodersDecoders(s, out var codec, true)) - return codec; - return null; - }); - ParsePartOfCodecs(res, "-decoders", (s) => - { - if (Codec.TryParseFromEncodersDecoders(s, out var codec, false)) - return codec; - return null; - }); - - return res; - } - - public static IReadOnlyList GetCodecs() - { - if (!FFMpegOptions.Options.UseCache) - return GetCodecsInternal().Values.ToList().AsReadOnly(); - return FFMpegCache.Codecs.Values.ToList().AsReadOnly(); - } - - public static IReadOnlyList GetCodecs(CodecType type) - { - if (!FFMpegOptions.Options.UseCache) - return GetCodecsInternal().Values.Where(x => x.Type == type).ToList().AsReadOnly(); - return FFMpegCache.Codecs.Values.Where(x=>x.Type == type).ToList().AsReadOnly(); - } - - public static IReadOnlyList GetVideoCodecs() => GetCodecs(CodecType.Video); - public static IReadOnlyList GetAudioCodecs() => GetCodecs(CodecType.Audio); - public static IReadOnlyList GetSubtitleCodecs() => GetCodecs(CodecType.Subtitle); - public static IReadOnlyList GetDataCodecs() => GetCodecs(CodecType.Data); - - public static bool TryGetCodec(string name, out Codec codec) - { - if (!FFMpegOptions.Options.UseCache) - { - codec = GetCodecsInternal().Values.FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim()); - return codec != null; - } - else - return FFMpegCache.Codecs.TryGetValue(name, out codec); - } - - public static Codec GetCodec(string name) - { - if (TryGetCodec(name, out var codec) && codec != null) - return codec; - throw new FFMpegException(FFMpegExceptionType.Operation, $"Codec \"{name}\" not supported"); - } - #endregion - - #region ContainerFormats - internal static IReadOnlyList GetContainersFormatsInternal() - { - FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); - - var list = new List(); - using var instance = new Instances.Instance(FFMpegOptions.Options.FFmpegBinary(), "-formats"); - instance.DataReceived += (e, args) => - { - if (ContainerFormat.TryParse(args.Data, out var fmt)) - list.Add(fmt); - }; - - var exitCode = instance.BlockUntilFinished(); - if (exitCode != 0) throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", instance.OutputData)); - - return list.AsReadOnly(); - } - - public static IReadOnlyList GetContainerFormats() - { - if (!FFMpegOptions.Options.UseCache) - return GetContainersFormatsInternal(); - return FFMpegCache.ContainerFormats.Values.ToList().AsReadOnly(); - } - - public static bool TryGetContainerFormat(string name, out ContainerFormat fmt) - { - if (!FFMpegOptions.Options.UseCache) - { - fmt = GetContainersFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim()); - return fmt != null; - } - else - return FFMpegCache.ContainerFormats.TryGetValue(name, out fmt); - } - - public static ContainerFormat GetContinerFormat(string name) - { - if (TryGetContainerFormat(name, out var fmt)) - return fmt; - throw new FFMpegException(FFMpegExceptionType.Operation, $"Container format \"{name}\" not supported"); - } - #endregion private static void Cleanup(IEnumerable pathList) { diff --git a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs index 3349e19..ab43d49 100644 --- a/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs +++ b/FFMpegCore/FFMpeg/FFMpegArgumentProcessor.cs @@ -4,8 +4,8 @@ using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; -using FFMpegCore.Exceptions; using FFMpegCore.Helpers; +using FFMpegCore.Models; using Instances; namespace FFMpegCore diff --git a/FFMpegCore/FFMpeg/FFMpegArguments.cs b/FFMpegCore/FFMpeg/FFMpegArguments.cs index bcfe28c..d0a3a2c 100644 --- a/FFMpegCore/FFMpeg/FFMpegArguments.cs +++ b/FFMpegCore/FFMpeg/FFMpegArguments.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using FFMpegCore.Arguments; using FFMpegCore.Enums; +using FFMpegCore.Models; using FFMpegCore.Pipes; namespace FFMpegCore @@ -85,8 +86,8 @@ private FFMpegArguments(IInputArgument inputArgument) public FFMpegArguments DrawText(DrawTextOptions drawTextOptions) => WithArgument(new DrawTextArgument(drawTextOptions)); - public FFMpegArgumentProcessor OutputToFile(string file, bool overwrite = false) => ToProcessor(new OutputArgument(file, overwrite)); - public FFMpegArgumentProcessor OutputToFile(Uri uri, bool overwrite = false) => ToProcessor(new OutputArgument(uri.AbsolutePath, overwrite)); + public FFMpegArgumentProcessor OutputToFile(string file, bool overwrite = false, bool verifyOutputExists = true) => ToProcessor(new OutputArgument(file, overwrite, verifyOutputExists)); + public FFMpegArgumentProcessor OutputToFile(Uri uri, bool overwrite = false, bool verifyOutputExists = true) => ToProcessor(new OutputArgument(uri.AbsolutePath, overwrite, verifyOutputExists)); public FFMpegArgumentProcessor OutputToPipe(IPipeDataReader reader) => ToProcessor(new OutputPipeArgument(reader)); public FFMpegArguments WithArgument(IArgument argument) @@ -106,7 +107,7 @@ internal void Pre() _inputArgument.Pre(); _outputArgument.Pre(); } - internal async Task During(CancellationToken? cancellationToken = null) + internal async Task During(CancellationToken cancellationToken) { await Task.WhenAll(_inputArgument.During(cancellationToken), _outputArgument.During(cancellationToken)).ConfigureAwait(false); } diff --git a/FFMpegCore/FFMpeg/FFMpegCache.cs b/FFMpegCore/FFMpeg/FFMpegCache.cs index 0847202..15d06bc 100644 --- a/FFMpegCore/FFMpeg/FFMpegCache.cs +++ b/FFMpegCore/FFMpeg/FFMpegCache.cs @@ -1,6 +1,6 @@ -using FFMpegCore.Enums; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; +using FFMpegCore.Models; namespace FFMpegCore { @@ -18,7 +18,7 @@ public static IReadOnlyDictionary PixelFormats if (_pixelFormats == null) //First check not thread safe lock (_syncObject) if (_pixelFormats == null)//Second check thread safe - _pixelFormats = FFMpeg.GetPixelFormatsInternal().ToDictionary(x => x.Name); + _pixelFormats = FFMpegUtils.GetPixelFormatsInternal().ToDictionary(x => x.Name); return _pixelFormats; } @@ -31,7 +31,7 @@ public static IReadOnlyDictionary Codecs if (_codecs == null) //First check not thread safe lock (_syncObject) if (_codecs == null)//Second check thread safe - _codecs = FFMpeg.GetCodecsInternal(); + _codecs = FFMpegUtils.GetCodecsInternal(); return _codecs; } @@ -44,7 +44,7 @@ public static IReadOnlyDictionary ContainerFormats if (_containers == null) //First check not thread safe lock (_syncObject) if (_containers == null)//Second check thread safe - _containers = FFMpeg.GetContainersFormatsInternal().ToDictionary(x => x.Name); + _containers = FFMpegUtils.GetContainersFormatsInternal().ToDictionary(x => x.Name); return _containers; } diff --git a/FFMpegCore/FFMpeg/FFMpegUtils.cs b/FFMpegCore/FFMpeg/FFMpegUtils.cs new file mode 100644 index 0000000..799ac3a --- /dev/null +++ b/FFMpegCore/FFMpeg/FFMpegUtils.cs @@ -0,0 +1,189 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using FFMpegCore.Enums; +using FFMpegCore.Helpers; +using FFMpegCore.Models; + +namespace FFMpegCore +{ + public static class FFMpegUtils + { + #region PixelFormats + internal static IReadOnlyList GetPixelFormatsInternal() + { + FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); + + var list = new List(); + using var instance = new Instances.Instance(FFMpegOptions.Options.FFmpegBinary(), "-pix_fmts"); + instance.DataReceived += (e, args) => + { + if (PixelFormat.TryParse(args.Data, out var fmt)) + list.Add(fmt); + }; + + var exitCode = instance.BlockUntilFinished(); + if (exitCode != 0) throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", instance.OutputData)); + + return list.AsReadOnly(); + } + + public static IReadOnlyList GetPixelFormats() + { + if (!FFMpegOptions.Options.UseCache) + return GetPixelFormatsInternal(); + return FFMpegCache.PixelFormats.Values.ToList().AsReadOnly(); + } + + public static bool TryGetPixelFormat(string name, out PixelFormat fmt) + { + if (!FFMpegOptions.Options.UseCache) + { + fmt = GetPixelFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim()); + return fmt != null; + } + else + return FFMpegCache.PixelFormats.TryGetValue(name, out fmt); + } + + public static PixelFormat GetPixelFormat(string name) + { + if (TryGetPixelFormat(name, out var fmt)) + return fmt; + throw new FFMpegException(FFMpegExceptionType.Operation, $"Pixel format \"{name}\" not supported"); + } + #endregion + + #region ContainerFormats + internal static IReadOnlyList GetContainersFormatsInternal() + { + FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); + + var list = new List(); + using var instance = new Instances.Instance(FFMpegOptions.Options.FFmpegBinary(), "-formats"); + instance.DataReceived += (e, args) => + { + if (ContainerFormat.TryParse(args.Data, out var fmt)) + list.Add(fmt); + }; + + var exitCode = instance.BlockUntilFinished(); + if (exitCode != 0) throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", instance.OutputData)); + + return list.AsReadOnly(); + } + + public static IReadOnlyList GetContainerFormats() + { + if (!FFMpegOptions.Options.UseCache) + return GetContainersFormatsInternal(); + return FFMpegCache.ContainerFormats.Values.ToList().AsReadOnly(); + } + + public static bool TryGetContainerFormat(string name, out ContainerFormat fmt) + { + if (!FFMpegOptions.Options.UseCache) + { + fmt = GetContainersFormatsInternal().FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim()); + return fmt != null; + } + else + return FFMpegCache.ContainerFormats.TryGetValue(name, out fmt); + } + + public static ContainerFormat GetContainerFormat(string name) + { + if (TryGetContainerFormat(name, out var fmt)) + return fmt; + throw new FFMpegException(FFMpegExceptionType.Operation, $"Container format \"{name}\" not supported"); + } + #endregion + + #region Codecs + + internal static void ParsePartOfCodecs(Dictionary codecs, string arguments, + Func parser) + { + FFMpegHelper.RootExceptionCheck(FFMpegOptions.Options.RootDirectory); + + using var instance = new Instances.Instance(FFMpegOptions.Options.FFmpegBinary(), arguments); + instance.DataReceived += (e, args) => + { + var codec = parser(args.Data); + if (codec != null) + if (codecs.TryGetValue(codec.Name, out var parentCodec)) + parentCodec.Merge(codec); + else + codecs.Add(codec.Name, codec); + }; + + var exitCode = instance.BlockUntilFinished(); + if (exitCode != 0) + throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", instance.OutputData)); + } + + internal static Dictionary GetCodecsInternal() + { + var res = new Dictionary(); + ParsePartOfCodecs(res, "-codecs", (s) => + { + if (Codec.TryParseFromCodecs(s, out var codec)) + return codec; + return null; + }); + ParsePartOfCodecs(res, "-encoders", (s) => + { + if (Codec.TryParseFromEncodersDecoders(s, out var codec, true)) + return codec; + return null; + }); + ParsePartOfCodecs(res, "-decoders", (s) => + { + if (Codec.TryParseFromEncodersDecoders(s, out var codec, false)) + return codec; + return null; + }); + + return res; + } + + public static IReadOnlyList GetCodecs() + { + if (!FFMpegOptions.Options.UseCache) + return GetCodecsInternal().Values.ToList().AsReadOnly(); + return FFMpegCache.Codecs.Values.ToList().AsReadOnly(); + } + + public static IReadOnlyList GetCodecs(CodecType type) + { + if (!FFMpegOptions.Options.UseCache) + return GetCodecsInternal().Values.Where(x => x.Type == type).ToList().AsReadOnly(); + return FFMpegCache.Codecs.Values.Where(x => x.Type == type).ToList().AsReadOnly(); + } + + public static IReadOnlyList GetVideoCodecs() => GetCodecs(CodecType.Video); + public static IReadOnlyList GetAudioCodecs() => GetCodecs(CodecType.Audio); + public static IReadOnlyList GetSubtitleCodecs() => GetCodecs(CodecType.Subtitle); + public static IReadOnlyList GetDataCodecs() => GetCodecs(CodecType.Data); + + public static bool TryGetCodec(string name, out Codec codec) + { + if (!FFMpegOptions.Options.UseCache) + { + codec = GetCodecsInternal().Values.FirstOrDefault(x => x.Name == name.ToLowerInvariant().Trim()); + return codec != null; + } + else + return FFMpegCache.Codecs.TryGetValue(name, out codec); + } + + public static Codec GetCodec(string name) + { + if (TryGetCodec(name, out var codec) && codec != null) + return codec; + throw new FFMpegException(FFMpegExceptionType.Operation, $"Codec \"{name}\" not supported"); + } + + #endregion + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Enums/Codec.cs b/FFMpegCore/FFMpeg/Models/Codec.cs similarity index 82% rename from FFMpegCore/FFMpeg/Enums/Codec.cs rename to FFMpegCore/FFMpeg/Models/Codec.cs index 1c4ce31..fdad529 100644 --- a/FFMpegCore/FFMpeg/Enums/Codec.cs +++ b/FFMpegCore/FFMpeg/Models/Codec.cs @@ -1,22 +1,13 @@ -using FFMpegCore.Exceptions; -using System; -using System.Collections.Generic; -using System.Text; +using System; using System.Text.RegularExpressions; +using FFMpegCore.Enums; -namespace FFMpegCore.Enums +namespace FFMpegCore.Models { - public enum FeatureStatus - { - Unknown, - NotSupported, - Supported, - } - public class Codec { - private static readonly Regex _codecsFormatRegex = new Regex(@"([D\.])([E\.])([VASD\.])([I\.])([L\.])([S\.])\s+([a-z0-9_-]+)\s+(.+)"); - private static readonly Regex _decodersEncodersFormatRegex = new Regex(@"([VASD\.])([F\.])([S\.])([X\.])([B\.])([D\.])\s+([a-z0-9_-]+)\s+(.+)"); + private static readonly Regex CodecsFormatRegex = new Regex(@"([D\.])([E\.])([VASD\.])([I\.])([L\.])([S\.])\s+([a-z0-9_-]+)\s+(.+)", RegexOptions.Compiled); + private static readonly Regex DecodersEncodersFormatRegex = new Regex(@"([VASD\.])([F\.])([S\.])([X\.])([B\.])([D\.])\s+([a-z0-9_-]+)\s+(.+)", RegexOptions.Compiled); public class FeatureLevel { @@ -58,7 +49,7 @@ internal Codec(string name, CodecType type) internal static bool TryParseFromCodecs(string line, out Codec codec) { - var match = _codecsFormatRegex.Match(line); + var match = CodecsFormatRegex.Match(line); if (!match.Success) { codec = null!; @@ -81,20 +72,21 @@ internal static bool TryParseFromCodecs(string line, out Codec codec) return false; } - codec = new Codec(name, type); - - codec.DecodingSupported = match.Groups[1].Value != "."; - codec.EncodingSupported = match.Groups[2].Value != "."; - codec.IsIntraFrameOnly = match.Groups[4].Value != "."; - codec.IsLossy = match.Groups[5].Value != "."; - codec.IsLossless = match.Groups[6].Value != "."; - codec.Description = match.Groups[8].Value; - + codec = new Codec(name, type) + { + DecodingSupported = match.Groups[1].Value != ".", + EncodingSupported = match.Groups[2].Value != ".", + IsIntraFrameOnly = match.Groups[4].Value != ".", + IsLossy = match.Groups[5].Value != ".", + IsLossless = match.Groups[6].Value != ".", + Description = match.Groups[8].Value + }; + return true; } internal static bool TryParseFromEncodersDecoders(string line, out Codec codec, bool isEncoder) { - var match = _decodersEncodersFormatRegex.Match(line); + var match = DecodersEncodersFormatRegex.Match(line); if (!match.Success) { codec = null!; @@ -135,7 +127,7 @@ internal static bool TryParseFromEncodersDecoders(string line, out Codec codec, internal void Merge(Codec other) { if (Name != other.Name) - throw new FFMpegException(FFMpegExceptionType.Operation, "different codecs enable to merge"); + throw new FFMpegException(FFMpegExceptionType.Operation, "different codecs unable to merge"); Type |= other.Type; DecodingSupported |= other.DecodingSupported; diff --git a/FFMpegCore/FFMpeg/Enums/ContainerFormat.cs b/FFMpegCore/FFMpeg/Models/ContainerFormat.cs similarity index 90% rename from FFMpegCore/FFMpeg/Enums/ContainerFormat.cs rename to FFMpegCore/FFMpeg/Models/ContainerFormat.cs index f15e5a7..6ef5b9c 100644 --- a/FFMpegCore/FFMpeg/Enums/ContainerFormat.cs +++ b/FFMpegCore/FFMpeg/Models/ContainerFormat.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; -namespace FFMpegCore.Enums +namespace FFMpegCore.Models { public class ContainerFormat { diff --git a/FFMpegCore/FFMpeg/Exceptions/FFMpegException.cs b/FFMpegCore/FFMpeg/Models/FFMpegException.cs similarity index 94% rename from FFMpegCore/FFMpeg/Exceptions/FFMpegException.cs rename to FFMpegCore/FFMpeg/Models/FFMpegException.cs index 6bd608d..592c4ff 100644 --- a/FFMpegCore/FFMpeg/Exceptions/FFMpegException.cs +++ b/FFMpegCore/FFMpeg/Models/FFMpegException.cs @@ -1,6 +1,6 @@ using System; -namespace FFMpegCore.Exceptions +namespace FFMpegCore.Models { public enum FFMpegExceptionType { diff --git a/FFMpegCore/FFMpeg/Enums/PixelFormat.cs b/FFMpegCore/FFMpeg/Models/PixelFormat.cs similarity index 84% rename from FFMpegCore/FFMpeg/Enums/PixelFormat.cs rename to FFMpegCore/FFMpeg/Models/PixelFormat.cs index 4262a74..275caa9 100644 --- a/FFMpegCore/FFMpeg/Enums/PixelFormat.cs +++ b/FFMpegCore/FFMpeg/Models/PixelFormat.cs @@ -1,13 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; -namespace FFMpegCore.Enums +namespace FFMpegCore.Models { public class PixelFormat { - private static readonly Regex _formatRegex = new Regex(@"([I\.])([O\.])([H\.])([P\.])([B\.])\s+(\S+)\s+([0-9]+)\s+([0-9]+)"); + private static readonly Regex FormatRegex = new Regex(@"([I\.])([O\.])([H\.])([P\.])([B\.])\s+(\S+)\s+([0-9]+)\s+([0-9]+)", RegexOptions.Compiled); public bool InputConversionSupported { get; private set; } public bool OutputConversionSupported { get; private set; } @@ -30,7 +27,7 @@ internal PixelFormat(string name) internal static bool TryParse(string line, out PixelFormat fmt) { - var match = _formatRegex.Match(line); + var match = FormatRegex.Match(line); if (!match.Success) { fmt = null!; diff --git a/FFMpegCore/FFMpeg/Pipes/RawVideoPipeDataWriter.cs b/FFMpegCore/FFMpeg/Pipes/RawVideoPipeDataWriter.cs index d35e7d5..c24e1cc 100644 --- a/FFMpegCore/FFMpeg/Pipes/RawVideoPipeDataWriter.cs +++ b/FFMpegCore/FFMpeg/Pipes/RawVideoPipeDataWriter.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; namespace FFMpegCore.Pipes { diff --git a/FFMpegCore/FFMpeg/Utils/AudioCodec.cs b/FFMpegCore/FFMpeg/Utils/AudioCodec.cs new file mode 100644 index 0000000..57a57b7 --- /dev/null +++ b/FFMpegCore/FFMpeg/Utils/AudioCodec.cs @@ -0,0 +1,14 @@ +using FFMpegCore.Models; + +namespace FFMpegCore.Utils +{ + public static class AudioCodec + { + public static Codec Aac => FFMpegUtils.GetCodec("aac"); + public static Codec LibVorbis => FFMpegUtils.GetCodec("libvorbis"); + public static Codec LibFdkAac => FFMpegUtils.GetCodec("libfdk_aac"); + public static Codec Ac3 => FFMpegUtils.GetCodec("ac3"); + public static Codec Eac3 => FFMpegUtils.GetCodec("eac3"); + public static Codec LibMp3Lame => FFMpegUtils.GetCodec("libmp3lame"); + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Enums/FileExtension.cs b/FFMpegCore/FFMpeg/Utils/FileExtension.cs similarity index 93% rename from FFMpegCore/FFMpeg/Enums/FileExtension.cs rename to FFMpegCore/FFMpeg/Utils/FileExtension.cs index d2e4a63..1673a84 100644 --- a/FFMpegCore/FFMpeg/Enums/FileExtension.cs +++ b/FFMpegCore/FFMpeg/Utils/FileExtension.cs @@ -1,6 +1,7 @@ using System; +using FFMpegCore.Models; -namespace FFMpegCore.Enums +namespace FFMpegCore.Utils { public static class FileExtension { diff --git a/FFMpegCore/FFMpeg/Utils/VideoCodec.cs b/FFMpegCore/FFMpeg/Utils/VideoCodec.cs new file mode 100644 index 0000000..b6b0752 --- /dev/null +++ b/FFMpegCore/FFMpeg/Utils/VideoCodec.cs @@ -0,0 +1,13 @@ +using FFMpegCore.Models; + +namespace FFMpegCore.Utils +{ + public static class VideoCodec + { + public static Codec LibX264 => FFMpegUtils.GetCodec("libx264"); + public static Codec LibVpx => FFMpegUtils.GetCodec("libvpx"); + public static Codec LibTheora => FFMpegUtils.GetCodec("libtheora"); + public static Codec Png => FFMpegUtils.GetCodec("png"); + public static Codec MpegTs => FFMpegUtils.GetCodec("mpegts"); + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpeg/Utils/VideoType.cs b/FFMpegCore/FFMpeg/Utils/VideoType.cs new file mode 100644 index 0000000..679ed8a --- /dev/null +++ b/FFMpegCore/FFMpeg/Utils/VideoType.cs @@ -0,0 +1,15 @@ +using FFMpegCore.Models; + +namespace FFMpegCore.Utils +{ + public static class VideoType + { + public static ContainerFormat MpegTs => FFMpegUtils.GetContainerFormat("mpegts"); + public static ContainerFormat Ts => FFMpegUtils.GetContainerFormat("mpegts"); + public static ContainerFormat Mp4 => FFMpegUtils.GetContainerFormat("mp4"); + public static ContainerFormat Mov => FFMpegUtils.GetContainerFormat("mov"); + public static ContainerFormat Avi => FFMpegUtils.GetContainerFormat("avi"); + public static ContainerFormat Ogv => FFMpegUtils.GetContainerFormat("ogv"); + public static ContainerFormat WebM => FFMpegUtils.GetContainerFormat("webm"); + } +} \ No newline at end of file diff --git a/FFMpegCore/FFMpegCore.csproj b/FFMpegCore/FFMpegCore.csproj index 996d76c..d9aaa89 100644 --- a/FFMpegCore/FFMpegCore.csproj +++ b/FFMpegCore/FFMpegCore.csproj @@ -32,8 +32,4 @@ - - - - diff --git a/FFMpegCore/FFProbe/FFProbe.cs b/FFMpegCore/FFProbe/FFProbe.cs index 8dc0154..7bcb4a0 100644 --- a/FFMpegCore/FFProbe/FFProbe.cs +++ b/FFMpegCore/FFProbe/FFProbe.cs @@ -1,10 +1,10 @@ -using System; -using System.IO; +using System.IO; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using FFMpegCore.Arguments; -using FFMpegCore.Exceptions; using FFMpegCore.Helpers; +using FFMpegCore.Models; using FFMpegCore.Pipes; using Instances; @@ -28,7 +28,7 @@ public static MediaAnalysis Analyse(System.IO.Stream stream, int outputCapacity var task = instance.FinishedRunning(); try { - pipeArgument.During().ConfigureAwait(false).GetAwaiter().GetResult(); + pipeArgument.During(CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult(); } catch (IOException) { } finally @@ -57,9 +57,9 @@ public static async Task AnalyseAsync(System.IO.Stream stream, in var task = instance.FinishedRunning(); try { - await pipeArgument.During(); + await pipeArgument.During(CancellationToken.None); } - catch(IOException) + catch (IOException) { } finally diff --git a/FFMpegCore/FFProbe/FFProbeAnalysis.cs b/FFMpegCore/FFProbe/FFProbeAnalysis.cs index 2a82528..8005d89 100644 --- a/FFMpegCore/FFProbe/FFProbeAnalysis.cs +++ b/FFMpegCore/FFProbe/FFProbeAnalysis.cs @@ -8,67 +8,4 @@ public class FFProbeAnalysis [JsonPropertyName("streams")] public List Streams { get; set; } = null!; } - - public class Stream - { - [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!; - - [JsonPropertyName("display_aspect_ratio")] - public string DisplayAspectRatio { get; set; } = null!; - - [JsonPropertyName("duration")] - public string Duration { get; set; } = null!; - - [JsonPropertyName("profile")] - public string Profile { get; set; } = null!; - - [JsonPropertyName("width")] - public int? Width { get; set; } - - [JsonPropertyName("height")] - public int? Height { get; set; } - - [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!; - - [JsonPropertyName("tags")] - public Tags Tags { get; set; } = null!; - } - - public class Tags - { - [JsonPropertyName("DURATION")] - public string Duration { get; set; } = null!; - } } diff --git a/FFMpegCore/FFProbe/MediaAnalysis.cs b/FFMpegCore/FFProbe/MediaAnalysis.cs index 4b638b2..07b7647 100644 --- a/FFMpegCore/FFProbe/MediaAnalysis.cs +++ b/FFMpegCore/FFProbe/MediaAnalysis.cs @@ -10,24 +10,29 @@ internal MediaAnalysis(string path, FFProbeAnalysis analysis) { VideoStreams = analysis.Streams.Where(stream => stream.CodecType == "video").Select(ParseVideoStream).ToList(); AudioStreams = analysis.Streams.Where(stream => stream.CodecType == "audio").Select(ParseAudioStream).ToList(); + TextStreams = analysis.Streams.Where(stream => stream.CodecTagString == "text").Select(ParseTextStream).ToList(); PrimaryVideoStream = VideoStreams.OrderBy(stream => stream.Index).FirstOrDefault(); PrimaryAudioStream = AudioStreams.OrderBy(stream => stream.Index).FirstOrDefault(); + PrimaryTextStream = TextStreams.OrderBy(stream => stream.Index).FirstOrDefault(); Path = path; } + public string Path { get; } public string Extension => System.IO.Path.GetExtension(Path); public TimeSpan Duration => TimeSpan.FromSeconds(Math.Max( PrimaryVideoStream?.Duration.TotalSeconds ?? 0, PrimaryAudioStream?.Duration.TotalSeconds ?? 0)); - public AudioStream PrimaryAudioStream { get; } public VideoStream PrimaryVideoStream { get; } + public AudioStream PrimaryAudioStream { get; } + public TextStream PrimaryTextStream { get; } public List VideoStreams { get; } public List AudioStreams { get; } + public List TextStreams { get; set; } private VideoStream ParseVideoStream(Stream stream) { @@ -45,7 +50,8 @@ private VideoStream ParseVideoStream(Stream stream) Height = stream.Height!.Value, Width = stream.Width!.Value, Profile = stream.Profile, - PixelFormat = stream.PixelFormat + PixelFormat = stream.PixelFormat, + Language = stream.Tags.Language }; } @@ -67,7 +73,19 @@ private AudioStream ParseAudioStream(Stream stream) Channels = stream.Channels ?? default, ChannelLayout = stream.ChannelLayout, Duration = TimeSpan.FromSeconds(ParseDoubleInvariant(stream.Duration ?? stream.Tags.Duration ?? "0")), - SampleRateHz = !string.IsNullOrEmpty(stream.SampleRate) ? ParseIntInvariant(stream.SampleRate) : default + SampleRateHz = !string.IsNullOrEmpty(stream.SampleRate) ? ParseIntInvariant(stream.SampleRate) : default, + Language = stream.Tags.Language + }; + } + private TextStream ParseTextStream(Stream stream) + { + return new TextStream + { + Index = stream.Index, + CodecName = stream.CodecName, + CodecLongName = stream.CodecLongName, + Duration = TimeSpan.FromSeconds(ParseDoubleInvariant(stream.Duration ?? stream.Tags.Duration ?? "0")), + Language = stream.Tags.Language }; } diff --git a/FFMpegCore/FFProbe/AudioStream.cs b/FFMpegCore/FFProbe/Models/AudioStream.cs similarity index 100% rename from FFMpegCore/FFProbe/AudioStream.cs rename to FFMpegCore/FFProbe/Models/AudioStream.cs diff --git a/FFMpegCore/FFProbe/Models/MediaStream.cs b/FFMpegCore/FFProbe/Models/MediaStream.cs new file mode 100644 index 0000000..61fc57b --- /dev/null +++ b/FFMpegCore/FFProbe/Models/MediaStream.cs @@ -0,0 +1,12 @@ +using FFMpegCore.Models; + +namespace FFMpegCore +{ + public abstract class MediaStream : SimpleStream + { + public int BitRate { get; internal set; } + + public Codec GetCodecInfo() => FFMpegUtils.GetCodec(CodecName); + + } +} \ No newline at end of file diff --git a/FFMpegCore/FFProbe/MediaStream.cs b/FFMpegCore/FFProbe/Models/SimpleStream.cs similarity index 59% rename from FFMpegCore/FFProbe/MediaStream.cs rename to FFMpegCore/FFProbe/Models/SimpleStream.cs index 8532e51..98a7804 100644 --- a/FFMpegCore/FFProbe/MediaStream.cs +++ b/FFMpegCore/FFProbe/Models/SimpleStream.cs @@ -1,16 +1,13 @@ -using FFMpegCore.Enums; -using System; +using System; namespace FFMpegCore { - public class MediaStream + public abstract class SimpleStream { public int Index { get; internal set; } public string CodecName { get; internal set; } = null!; public string CodecLongName { get; internal set; } = null!; - public int BitRate { get; internal set; } public TimeSpan Duration { get; internal set; } - - public Codec GetCodecInfo() => FFMpeg.GetCodec(CodecName); + public string? Language { get; internal set; } } } \ No newline at end of file diff --git a/FFMpegCore/FFProbe/Models/TextStream.cs b/FFMpegCore/FFProbe/Models/TextStream.cs new file mode 100644 index 0000000..61d691e --- /dev/null +++ b/FFMpegCore/FFProbe/Models/TextStream.cs @@ -0,0 +1,7 @@ +namespace FFMpegCore +{ + public class TextStream : SimpleStream + { + + } +} \ No newline at end of file diff --git a/FFMpegCore/FFProbe/VideoStream.cs b/FFMpegCore/FFProbe/Models/VideoStream.cs similarity index 82% rename from FFMpegCore/FFProbe/VideoStream.cs rename to FFMpegCore/FFProbe/Models/VideoStream.cs index 18533bd..0ebf202 100644 --- a/FFMpegCore/FFProbe/VideoStream.cs +++ b/FFMpegCore/FFProbe/Models/VideoStream.cs @@ -1,4 +1,4 @@ -using FFMpegCore.Enums; +using FFMpegCore.Models; namespace FFMpegCore { @@ -13,6 +13,6 @@ public class VideoStream : MediaStream public double FrameRate { get; internal set; } public string PixelFormat { get; internal set; } = null!; - public PixelFormat GetPixelFormatInfo() => FFMpeg.GetPixelFormat(PixelFormat); + public PixelFormat GetPixelFormatInfo() => FFMpegUtils.GetPixelFormat(PixelFormat); } } \ No newline at end of file diff --git a/FFMpegCore/FFProbe/Stream.cs b/FFMpegCore/FFProbe/Stream.cs new file mode 100644 index 0000000..8ac2ca7 --- /dev/null +++ b/FFMpegCore/FFProbe/Stream.cs @@ -0,0 +1,64 @@ +using System.Text.Json.Serialization; + +namespace FFMpegCore +{ + public class Stream + { + [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!; + + [JsonPropertyName("codec_tag_string")] + public string CodecTagString { get; set; } = null!; + + [JsonPropertyName("display_aspect_ratio")] + public string DisplayAspectRatio { get; set; } = null!; + + [JsonPropertyName("duration")] + public string Duration { get; set; } = null!; + + [JsonPropertyName("profile")] + public string Profile { get; set; } = null!; + + [JsonPropertyName("width")] + public int? Width { get; set; } + + [JsonPropertyName("height")] + public int? Height { get; set; } + + [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!; + + [JsonPropertyName("tags")] + public Tags Tags { get; set; } = null!; + } +} \ No newline at end of file diff --git a/FFMpegCore/FFProbe/Tags.cs b/FFMpegCore/FFProbe/Tags.cs new file mode 100644 index 0000000..8feaa8d --- /dev/null +++ b/FFMpegCore/FFProbe/Tags.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace FFMpegCore +{ + public class Tags + { + [JsonPropertyName("duration")] + public string Duration { get; set; } = null!; + + [JsonPropertyName("language")] + public string Language { get; set; } = null!; + } +} \ No newline at end of file diff --git a/FFMpegCore/Helpers/FFMpegHelper.cs b/FFMpegCore/Helpers/FFMpegHelper.cs index f280b08..457e014 100644 --- a/FFMpegCore/Helpers/FFMpegHelper.cs +++ b/FFMpegCore/Helpers/FFMpegHelper.cs @@ -1,7 +1,7 @@ using System; using System.Drawing; using System.IO; -using FFMpegCore.Exceptions; +using FFMpegCore.Models; namespace FFMpegCore.Helpers { diff --git a/FFMpegCore/Helpers/FFProbeHelper.cs b/FFMpegCore/Helpers/FFProbeHelper.cs index eed1b7a..cc4289d 100644 --- a/FFMpegCore/Helpers/FFProbeHelper.cs +++ b/FFMpegCore/Helpers/FFProbeHelper.cs @@ -1,4 +1,4 @@ -using FFMpegCore.Exceptions; +using FFMpegCore.Models; namespace FFMpegCore.Helpers { diff --git a/FFMpegCore/ImageInfo.cs b/FFMpegCore/ImageInfo.cs index cf8561e..a178e2c 100644 --- a/FFMpegCore/ImageInfo.cs +++ b/FFMpegCore/ImageInfo.cs @@ -1,8 +1,8 @@ using System; using System.Drawing; using System.IO; -using FFMpegCore.Enums; using FFMpegCore.Helpers; +using FFMpegCore.Utils; namespace FFMpegCore {