Decompiled source of FFMpegCore v5.1.1

BepInEx/core/FFMpegCore/netstandard2.0/FFMpegCore.dll

Decompiled 4 days ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using FFMpegCore.Arguments;
using FFMpegCore.Builders.MetaData;
using FFMpegCore.Enums;
using FFMpegCore.Exceptions;
using FFMpegCore.Extend;
using FFMpegCore.Helpers;
using FFMpegCore.Pipes;
using Instances;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("FFMpegCore.Test")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Malte Rosenbjerg, Vlad Jerca, Max Bagryantsev")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("A .NET Standard FFMpeg/FFProbe wrapper for easily integrating media analysis and conversion into your .NET applications")]
[assembly: AssemblyFileVersion("5.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("FFMpegCore")]
[assembly: AssemblyTitle("FFMpegCore")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/rosenbjerg/FFMpegCore")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: AssemblyVersion("5.0.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace FFMpegCore
{
	public static class FFMpeg
	{
		public static bool Snapshot(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
		{
			if (Path.GetExtension(output) != FileExtension.Png)
			{
				output = Path.Combine(Path.GetDirectoryName(output), Path.GetFileNameWithoutExtension(output) + FileExtension.Png);
			}
			IMediaAnalysis source = FFProbe.Analyse(input);
			var (fFMpegArguments, addArguments) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, source, size, captureTime, streamIndex, inputFileIndex);
			return fFMpegArguments.OutputToFile(output, overwrite: true, addArguments).ProcessSynchronously();
		}

		public static async Task<bool> SnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
		{
			if (Path.GetExtension(output) != FileExtension.Png)
			{
				output = Path.Combine(Path.GetDirectoryName(output), Path.GetFileNameWithoutExtension(output) + FileExtension.Png);
			}
			var (fFMpegArguments, addArguments) = SnapshotArgumentBuilder.BuildSnapshotArguments(input, await FFProbe.AnalyseAsync(input).ConfigureAwait(continueOnCapturedContext: false), size, captureTime, streamIndex, inputFileIndex);
			return await fFMpegArguments.OutputToFile(output, overwrite: true, addArguments).ProcessAsynchronously();
		}

		public static bool GifSnapshot(string input, string output, Size? size = null, TimeSpan? captureTime = null, TimeSpan? duration = null, int? streamIndex = null)
		{
			if (Path.GetExtension(output)?.ToLower() != FileExtension.Gif)
			{
				output = Path.Combine(Path.GetDirectoryName(output), Path.GetFileNameWithoutExtension(output) + FileExtension.Gif);
			}
			IMediaAnalysis source = FFProbe.Analyse(input);
			var (fFMpegArguments, addArguments) = SnapshotArgumentBuilder.BuildGifSnapshotArguments(input, source, size, captureTime, duration, streamIndex);
			return fFMpegArguments.OutputToFile(output, overwrite: true, addArguments).ProcessSynchronously();
		}

		public static async Task<bool> GifSnapshotAsync(string input, string output, Size? size = null, TimeSpan? captureTime = null, TimeSpan? duration = null, int? streamIndex = null)
		{
			if (Path.GetExtension(output)?.ToLower() != FileExtension.Gif)
			{
				output = Path.Combine(Path.GetDirectoryName(output), Path.GetFileNameWithoutExtension(output) + FileExtension.Gif);
			}
			var (fFMpegArguments, addArguments) = SnapshotArgumentBuilder.BuildGifSnapshotArguments(input, await FFProbe.AnalyseAsync(input).ConfigureAwait(continueOnCapturedContext: false), size, captureTime, duration, streamIndex);
			return await fFMpegArguments.OutputToFile(output, overwrite: true, addArguments).ProcessAsynchronously();
		}

		public static bool JoinImageSequence(string output, double frameRate = 30.0, params string[] images)
		{
			string?[] array = images.Select(Path.GetExtension).Distinct().ToArray();
			if (array.Length != 1)
			{
				throw new ArgumentException("All images must have the same extension", "images");
			}
			string text = array[0].ToLowerInvariant();
			int? width = null;
			int? height = null;
			string text2 = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Guid.NewGuid().ToString());
			Directory.CreateDirectory(text2);
			try
			{
				int num = 0;
				foreach (string obj in images)
				{
					IMediaAnalysis mediaAnalysis = FFProbe.Analyse(obj);
					FFMpegHelper.ConversionSizeExceptionCheck(mediaAnalysis.PrimaryVideoStream.Width, mediaAnalysis.PrimaryVideoStream.Height);
					int valueOrDefault = width.GetValueOrDefault();
					if (!width.HasValue)
					{
						valueOrDefault = mediaAnalysis.PrimaryVideoStream.Width;
						width = valueOrDefault;
					}
					valueOrDefault = height.GetValueOrDefault();
					if (!height.HasValue)
					{
						valueOrDefault = mediaAnalysis.PrimaryVideoStream.Height;
						height = valueOrDefault;
					}
					string destFileName = Path.Combine(text2, num++.ToString().PadLeft(9, '0') + text);
					File.Copy(obj, destFileName);
				}
				return FFMpegArguments.FromFileInput(Path.Combine(text2, "%09d" + text), verifyExists: false).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
				{
					options.ForcePixelFormat("yuv420p").Resize(width.Value, height.Value).WithFramerate(frameRate);
				}).ProcessSynchronously();
			}
			finally
			{
				Directory.Delete(text2, recursive: true);
			}
		}

		public static bool PosterWithAudio(string image, string audio, string output)
		{
			FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4);
			IMediaAnalysis mediaAnalysis = FFProbe.Analyse(image);
			FFMpegHelper.ConversionSizeExceptionCheck(mediaAnalysis.PrimaryVideoStream.Width, mediaAnalysis.PrimaryVideoStream.Height);
			return FFMpegArguments.FromFileInput(image, verifyExists: false, delegate(FFMpegArgumentOptions options)
			{
				options.Loop(1).ForceFormat("image2");
			}).AddFileInput(audio).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
			{
				options.ForcePixelFormat("yuv420p").WithVideoCodec(VideoCodec.LibX264).WithConstantRateFactor(21)
					.WithAudioBitrate(AudioQuality.Normal)
					.UsingShortest();
			})
				.ProcessSynchronously();
		}

		public static bool Convert(string input, string output, ContainerFormat format, Speed speed = Speed.SuperFast, VideoSize size = VideoSize.Original, AudioQuality audioQuality = AudioQuality.Normal, bool multithreaded = false)
		{
			FFMpegHelper.ExtensionExceptionCheck(output, format.Extension);
			IMediaAnalysis mediaAnalysis = FFProbe.Analyse(input);
			FFMpegHelper.ConversionSizeExceptionCheck(mediaAnalysis);
			double num = ((VideoSize.Original == size) ? 1.0 : ((double)mediaAnalysis.PrimaryVideoStream.Height / (double)size));
			Size outputSize = new Size((int)((double)mediaAnalysis.PrimaryVideoStream.Width / num), (int)((double)mediaAnalysis.PrimaryVideoStream.Height / num));
			if (outputSize.Width % 2 != 0)
			{
				outputSize.Width++;
			}
			return format.Name switch
			{
				"mp4" => FFMpegArguments.FromFileInput(input).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
				{
					options.UsingMultithreading(multithreaded).WithVideoCodec(VideoCodec.LibX264).WithVideoBitrate(2400)
						.WithVideoFilters(delegate(VideoFilterOptions filterOptions)
						{
							filterOptions.Scale(outputSize);
						})
						.WithSpeedPreset(speed)
						.WithAudioCodec(AudioCodec.Aac)
						.WithAudioBitrate(audioQuality);
				}).ProcessSynchronously(), 
				"ogv" => FFMpegArguments.FromFileInput(input).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
				{
					options.UsingMultithreading(multithreaded).WithVideoCodec(VideoCodec.LibTheora).WithVideoBitrate(2400)
						.WithVideoFilters(delegate(VideoFilterOptions filterOptions)
						{
							filterOptions.Scale(outputSize);
						})
						.WithSpeedPreset(speed)
						.WithAudioCodec(AudioCodec.LibVorbis)
						.WithAudioBitrate(audioQuality);
				}).ProcessSynchronously(), 
				"mpegts" => FFMpegArguments.FromFileInput(input).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
				{
					options.CopyChannel().WithBitStreamFilter(Channel.Video, Filter.H264_Mp4ToAnnexB).ForceFormat(VideoType.Ts);
				}).ProcessSynchronously(), 
				"webm" => FFMpegArguments.FromFileInput(input).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
				{
					options.UsingMultithreading(multithreaded).WithVideoCodec(VideoCodec.LibVpx).WithVideoBitrate(2400)
						.WithVideoFilters(delegate(VideoFilterOptions filterOptions)
						{
							filterOptions.Scale(outputSize);
						})
						.WithSpeedPreset(speed)
						.WithAudioCodec(AudioCodec.LibVorbis)
						.WithAudioBitrate(audioQuality);
				}).ProcessSynchronously(), 
				_ => throw new ArgumentOutOfRangeException("format"), 
			};
		}

		public static bool Join(string output, params string[] videos)
		{
			string[] array = videos.Select(delegate(string videoPath)
			{
				FFMpegHelper.ConversionSizeExceptionCheck(FFProbe.Analyse(videoPath));
				string text = Path.Combine(GlobalFFOptions.Current.TemporaryFilesFolder, Path.GetFileNameWithoutExtension(videoPath) + FileExtension.Ts);
				Directory.CreateDirectory(GlobalFFOptions.Current.TemporaryFilesFolder);
				Convert(videoPath, text, VideoType.Ts);
				return text;
			}).ToArray();
			try
			{
				return FFMpegArguments.FromConcatInput(array).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
				{
					options.CopyChannel().WithBitStreamFilter(Channel.Audio, Filter.Aac_AdtstoAsc);
				}).ProcessSynchronously();
			}
			finally
			{
				Cleanup(array);
			}
		}

		private static FFMpegArgumentProcessor BaseSubVideo(string input, string output, TimeSpan startTime, TimeSpan endTime)
		{
			if (Path.GetExtension(input) != Path.GetExtension(output))
			{
				output = Path.Combine(Path.GetDirectoryName(output), Path.GetFileNameWithoutExtension(output), Path.GetExtension(input));
			}
			return FFMpegArguments.FromFileInput(input, verifyExists: true, delegate(FFMpegArgumentOptions options)
			{
				options.Seek(startTime).EndSeek(endTime);
			}).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
			{
				options.CopyChannel();
			});
		}

		public static bool SubVideo(string input, string output, TimeSpan startTime, TimeSpan endTime)
		{
			return BaseSubVideo(input, output, startTime, endTime).ProcessSynchronously();
		}

		public static async Task<bool> SubVideoAsync(string input, string output, TimeSpan startTime, TimeSpan endTime)
		{
			return await BaseSubVideo(input, output, startTime, endTime).ProcessAsynchronously();
		}

		public static bool SaveM3U8Stream(Uri uri, string output)
		{
			FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp4);
			if (uri.Scheme != "http" && uri.Scheme != "https")
			{
				throw new ArgumentException("Uri: " + uri.AbsoluteUri + ", does not point to a valid http(s) stream.");
			}
			return FFMpegArguments.FromUrlInput(uri).OutputToFile(output).ProcessSynchronously();
		}

		public static bool Mute(string input, string output)
		{
			FFMpegHelper.ConversionSizeExceptionCheck(FFProbe.Analyse(input));
			return FFMpegArguments.FromFileInput(input).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
			{
				options.CopyChannel(Channel.Video).DisableChannel(Channel.Audio);
			}).ProcessSynchronously();
		}

		public static bool ExtractAudio(string input, string output)
		{
			FFMpegHelper.ExtensionExceptionCheck(output, FileExtension.Mp3);
			return FFMpegArguments.FromFileInput(input).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
			{
				options.DisableChannel(Channel.Video);
			}).ProcessSynchronously();
		}

		public static bool ReplaceAudio(string input, string inputAudio, string output, bool stopAtShortest = false)
		{
			FFMpegHelper.ConversionSizeExceptionCheck(FFProbe.Analyse(input));
			return FFMpegArguments.FromFileInput(input).AddFileInput(inputAudio).OutputToFile(output, overwrite: true, delegate(FFMpegArgumentOptions options)
			{
				options.CopyChannel().WithAudioCodec(AudioCodec.Aac).WithAudioBitrate(AudioQuality.Good)
					.UsingShortest(stopAtShortest);
			})
				.ProcessSynchronously();
		}

		internal static IReadOnlyList<PixelFormat> GetPixelFormatsInternal()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			FFMpegHelper.RootExceptionCheck();
			List<PixelFormat> list = new List<PixelFormat>();
			ProcessArguments val = new ProcessArguments(GlobalFFOptions.GetFFMpegBinaryPath(), "-pix_fmts");
			val.OutputDataReceived += delegate(object e, string data)
			{
				if (PixelFormat.TryParse(data, out PixelFormat fmt))
				{
					list.Add(fmt);
				}
			};
			IProcessResult val2 = ProcessArgumentsExtensions.StartAndWaitForExit(val);
			if (val2.ExitCode != 0)
			{
				throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", val2.OutputData));
			}
			return list.AsReadOnly();
		}

		public static IReadOnlyList<PixelFormat> GetPixelFormats()
		{
			if (!GlobalFFOptions.Current.UseCache)
			{
				return GetPixelFormatsInternal();
			}
			return FFMpegCache.PixelFormats.Values.ToList().AsReadOnly();
		}

		public static bool TryGetPixelFormat(string name, out PixelFormat format)
		{
			string name2 = name;
			if (!GlobalFFOptions.Current.UseCache)
			{
				format = GetPixelFormatsInternal().FirstOrDefault((PixelFormat x) => x.Name == name2.ToLowerInvariant().Trim());
				return format != null;
			}
			return FFMpegCache.PixelFormats.TryGetValue(name2, out format);
		}

		public static PixelFormat GetPixelFormat(string name)
		{
			if (TryGetPixelFormat(name, out PixelFormat format))
			{
				return format;
			}
			throw new FFMpegException(FFMpegExceptionType.Operation, "Pixel format \"" + name + "\" not supported");
		}

		private static void ParsePartOfCodecs(Dictionary<string, Codec> codecs, string arguments, Func<string, Codec?> parser)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			Func<string, Codec?> parser2 = parser;
			Dictionary<string, Codec> codecs2 = codecs;
			FFMpegHelper.RootExceptionCheck();
			ProcessArguments val = new ProcessArguments(GlobalFFOptions.GetFFMpegBinaryPath(), arguments);
			val.OutputDataReceived += delegate(object e, string data)
			{
				Codec codec = parser2(data);
				if (codec != null)
				{
					if (codecs2.TryGetValue(codec.Name, out Codec value))
					{
						value.Merge(codec);
					}
					else
					{
						codecs2.Add(codec.Name, codec);
					}
				}
			};
			IProcessResult val2 = ProcessArgumentsExtensions.StartAndWaitForExit(val);
			if (val2.ExitCode != 0)
			{
				throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", val2.OutputData));
			}
		}

		internal static Dictionary<string, Codec> GetCodecsInternal()
		{
			Dictionary<string, Codec> dictionary = new Dictionary<string, Codec>();
			ParsePartOfCodecs(dictionary, "-codecs", (string s) => Codec.TryParseFromCodecs(s, out Codec codec3) ? codec3 : null);
			ParsePartOfCodecs(dictionary, "-encoders", (string s) => Codec.TryParseFromEncodersDecoders(s, out Codec codec2, isEncoder: true) ? codec2 : null);
			ParsePartOfCodecs(dictionary, "-decoders", (string s) => Codec.TryParseFromEncodersDecoders(s, out Codec codec, isEncoder: false) ? codec : null);
			return dictionary;
		}

		public static IReadOnlyList<Codec> GetCodecs()
		{
			if (!GlobalFFOptions.Current.UseCache)
			{
				return GetCodecsInternal().Values.ToList().AsReadOnly();
			}
			return FFMpegCache.Codecs.Values.ToList().AsReadOnly();
		}

		public static IReadOnlyList<Codec> GetCodecs(CodecType type)
		{
			if (!GlobalFFOptions.Current.UseCache)
			{
				return GetCodecsInternal().Values.Where((Codec x) => x.Type == type).ToList().AsReadOnly();
			}
			return FFMpegCache.Codecs.Values.Where((Codec x) => x.Type == type).ToList().AsReadOnly();
		}

		public static IReadOnlyList<Codec> GetVideoCodecs()
		{
			return GetCodecs(CodecType.Video);
		}

		public static IReadOnlyList<Codec> GetAudioCodecs()
		{
			return GetCodecs(CodecType.Audio);
		}

		public static IReadOnlyList<Codec> GetSubtitleCodecs()
		{
			return GetCodecs(CodecType.Subtitle);
		}

		public static IReadOnlyList<Codec> GetDataCodecs()
		{
			return GetCodecs(CodecType.Data);
		}

		public static bool TryGetCodec(string name, out Codec codec)
		{
			string name2 = name;
			if (!GlobalFFOptions.Current.UseCache)
			{
				codec = GetCodecsInternal().Values.FirstOrDefault((Codec x) => x.Name == name2.ToLowerInvariant().Trim());
				return codec != null;
			}
			return FFMpegCache.Codecs.TryGetValue(name2, out codec);
		}

		public static Codec GetCodec(string name)
		{
			if (TryGetCodec(name, out Codec codec) && codec != null)
			{
				return codec;
			}
			throw new FFMpegException(FFMpegExceptionType.Operation, "Codec \"" + name + "\" not supported");
		}

		internal static IReadOnlyList<ContainerFormat> GetContainersFormatsInternal()
		{
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Expected O, but got Unknown
			FFMpegHelper.RootExceptionCheck();
			List<ContainerFormat> list = new List<ContainerFormat>();
			ProcessArguments val = new ProcessArguments(GlobalFFOptions.GetFFMpegBinaryPath(), "-formats");
			val.OutputDataReceived += delegate(object e, string data)
			{
				if (ContainerFormat.TryParse(data, out ContainerFormat fmt))
				{
					list.Add(fmt);
				}
			};
			IProcessResult val2 = ProcessArgumentsExtensions.StartAndWaitForExit(val);
			if (val2.ExitCode != 0)
			{
				throw new FFMpegException(FFMpegExceptionType.Process, string.Join("\r\n", val2.OutputData));
			}
			return list.AsReadOnly();
		}

		public static IReadOnlyList<ContainerFormat> GetContainerFormats()
		{
			if (!GlobalFFOptions.Current.UseCache)
			{
				return GetContainersFormatsInternal();
			}
			return FFMpegCache.ContainerFormats.Values.ToList().AsReadOnly();
		}

		public static bool TryGetContainerFormat(string name, out ContainerFormat fmt)
		{
			string name2 = name;
			if (!GlobalFFOptions.Current.UseCache)
			{
				fmt = GetContainersFormatsInternal().FirstOrDefault((ContainerFormat x) => x.Name == name2.ToLowerInvariant().Trim());
				return fmt != null;
			}
			return FFMpegCache.ContainerFormats.TryGetValue(name2, out fmt);
		}

		public static ContainerFormat GetContainerFormat(string name)
		{
			if (TryGetContainerFormat(name, out ContainerFormat fmt))
			{
				return fmt;
			}
			throw new FFMpegException(FFMpegExceptionType.Operation, "Container format \"" + name + "\" not supported");
		}

		private static void Cleanup(IEnumerable<string> pathList)
		{
			foreach (string path in pathList)
			{
				if (File.Exists(path))
				{
					File.Delete(path);
				}
			}
		}
	}
	public class FFMpegArgumentOptions : FFMpegArgumentsBase
	{
		internal FFMpegArgumentOptions()
		{
		}

		public FFMpegArgumentOptions WithAudioCodec(Codec audioCodec)
		{
			return WithArgument(new AudioCodecArgument(audioCodec));
		}

		public FFMpegArgumentOptions WithAudioCodec(string audioCodec)
		{
			return WithArgument(new AudioCodecArgument(audioCodec));
		}

		public FFMpegArgumentOptions WithAudioBitrate(AudioQuality audioQuality)
		{
			return WithArgument(new AudioBitrateArgument(audioQuality));
		}

		public FFMpegArgumentOptions WithAudioBitrate(int bitrate)
		{
			return WithArgument(new AudioBitrateArgument(bitrate));
		}

		public FFMpegArgumentOptions WithAudioSamplingRate(int samplingRate = 48000)
		{
			return WithArgument(new AudioSamplingRateArgument(samplingRate));
		}

		public FFMpegArgumentOptions WithVariableBitrate(int vbr)
		{
			return WithArgument(new VariableBitRateArgument(vbr));
		}

		public FFMpegArgumentOptions Resize(int width, int height)
		{
			return WithArgument(new SizeArgument(width, height));
		}

		public FFMpegArgumentOptions Resize(Size? size)
		{
			return WithArgument(new SizeArgument(size));
		}

		public FFMpegArgumentOptions WithBitStreamFilter(Channel channel, Filter filter)
		{
			return WithArgument(new BitStreamFilterArgument(channel, filter));
		}

		public FFMpegArgumentOptions WithConstantRateFactor(int crf)
		{
			return WithArgument(new ConstantRateFactorArgument(crf));
		}

		public FFMpegArgumentOptions CopyChannel(Channel channel = Channel.Both)
		{
			return WithArgument(new CopyArgument(channel));
		}

		public FFMpegArgumentOptions DisableChannel(Channel channel)
		{
			return WithArgument(new DisableChannelArgument(channel));
		}

		public FFMpegArgumentOptions WithDuration(TimeSpan? duration)
		{
			return WithArgument(new DurationArgument(duration));
		}

		public FFMpegArgumentOptions WithFastStart()
		{
			return WithArgument(new FaststartArgument());
		}

		public FFMpegArgumentOptions WithFrameOutputCount(int frames)
		{
			return WithArgument(new FrameOutputCountArgument(frames));
		}

		public FFMpegArgumentOptions WithHardwareAcceleration(HardwareAccelerationDevice hardwareAccelerationDevice = HardwareAccelerationDevice.Auto)
		{
			return WithArgument(new HardwareAccelerationArgument(hardwareAccelerationDevice));
		}

		public FFMpegArgumentOptions UsingShortest(bool shortest = true)
		{
			return WithArgument(new ShortestArgument(shortest));
		}

		public FFMpegArgumentOptions UsingMultithreading(bool multithread)
		{
			return WithArgument(new ThreadsArgument(multithread));
		}

		public FFMpegArgumentOptions UsingThreads(int threads)
		{
			return WithArgument(new ThreadsArgument(threads));
		}

		public FFMpegArgumentOptions WithVideoCodec(Codec videoCodec)
		{
			return WithArgument(new VideoCodecArgument(videoCodec));
		}

		public FFMpegArgumentOptions WithVideoCodec(string videoCodec)
		{
			return WithArgument(new VideoCodecArgument(videoCodec));
		}

		public FFMpegArgumentOptions WithVideoBitrate(int bitrate)
		{
			return WithArgument(new VideoBitrateArgument(bitrate));
		}

		public FFMpegArgumentOptions WithVideoFilters(Action<VideoFilterOptions> videoFilterOptions)
		{
			VideoFilterOptions videoFilterOptions2 = new VideoFilterOptions();
			videoFilterOptions(videoFilterOptions2);
			return WithArgument(new VideoFiltersArgument(videoFilterOptions2));
		}

		public FFMpegArgumentOptions WithAudioFilters(Action<AudioFilterOptions> audioFilterOptions)
		{
			AudioFilterOptions audioFilterOptions2 = new AudioFilterOptions();
			audioFilterOptions(audioFilterOptions2);
			return WithArgument(new AudioFiltersArgument(audioFilterOptions2));
		}

		public FFMpegArgumentOptions WithFramerate(double framerate)
		{
			return WithArgument(new FrameRateArgument(framerate));
		}

		public FFMpegArgumentOptions WithoutMetadata()
		{
			return WithArgument(new RemoveMetadataArgument());
		}

		public FFMpegArgumentOptions WithSpeedPreset(Speed speed)
		{
			return WithArgument(new SpeedPresetArgument(speed));
		}

		public FFMpegArgumentOptions WithStartNumber(int startNumber)
		{
			return WithArgument(new StartNumberArgument(startNumber));
		}

		public FFMpegArgumentOptions WithCustomArgument(string argument)
		{
			return WithArgument(new CustomArgument(argument));
		}

		public FFMpegArgumentOptions Seek(TimeSpan? seekTo)
		{
			return WithArgument(new SeekArgument(seekTo));
		}

		public FFMpegArgumentOptions EndSeek(TimeSpan? seekTo)
		{
			return WithArgument(new EndSeekArgument(seekTo));
		}

		public FFMpegArgumentOptions Loop(int times)
		{
			return WithArgument(new LoopArgument(times));
		}

		public FFMpegArgumentOptions OverwriteExisting()
		{
			return WithArgument(new OverwriteArgument());
		}

		public FFMpegArgumentOptions SelectStream(int streamIndex, int inputFileIndex = 0, Channel channel = Channel.All)
		{
			return WithArgument(new MapStreamArgument(streamIndex, inputFileIndex, channel));
		}

		public FFMpegArgumentOptions SelectStreams(IEnumerable<int> streamIndices, int inputFileIndex = 0, Channel channel = Channel.All)
		{
			return streamIndices.Aggregate(this, (FFMpegArgumentOptions options, int streamIndex) => options.SelectStream(streamIndex, inputFileIndex, channel));
		}

		public FFMpegArgumentOptions DeselectStream(int streamIndex, int inputFileIndex = 0, Channel channel = Channel.All)
		{
			return WithArgument(new MapStreamArgument(streamIndex, inputFileIndex, channel, negativeMap: true));
		}

		public FFMpegArgumentOptions DeselectStreams(IEnumerable<int> streamIndices, int inputFileIndex = 0, Channel channel = Channel.All)
		{
			return streamIndices.Aggregate(this, (FFMpegArgumentOptions options, int streamIndex) => options.DeselectStream(streamIndex, inputFileIndex, channel));
		}

		public FFMpegArgumentOptions ForceFormat(ContainerFormat format)
		{
			return WithArgument(new ForceFormatArgument(format));
		}

		public FFMpegArgumentOptions ForceFormat(string format)
		{
			return WithArgument(new ForceFormatArgument(format));
		}

		public FFMpegArgumentOptions ForcePixelFormat(string pixelFormat)
		{
			return WithArgument(new ForcePixelFormat(pixelFormat));
		}

		public FFMpegArgumentOptions ForcePixelFormat(PixelFormat pixelFormat)
		{
			return WithArgument(new ForcePixelFormat(pixelFormat));
		}

		public FFMpegArgumentOptions WithAudibleEncryptionKeys(string key, string iv)
		{
			return WithArgument(new AudibleEncryptionKeyArgument(key, iv));
		}

		public FFMpegArgumentOptions WithAudibleActivationBytes(string activationBytes)
		{
			return WithArgument(new AudibleEncryptionKeyArgument(activationBytes));
		}

		public FFMpegArgumentOptions WithTagVersion(int id3v2Version = 3)
		{
			return WithArgument(new ID3V2VersionArgument(id3v2Version));
		}

		public FFMpegArgumentOptions WithGifPaletteArgument(int streamIndex, Size? size, int fps = 12)
		{
			return WithArgument(new GifPaletteArgument(streamIndex, fps, size));
		}

		public FFMpegArgumentOptions WithArgument(IArgument argument)
		{
			Arguments.Add(argument);
			return this;
		}
	}
	public class FFMpegArgumentProcessor
	{
		private static readonly Regex ProgressRegex = new Regex("time=(\\d\\d:\\d\\d:\\d\\d.\\d\\d?)", RegexOptions.Compiled);

		private readonly List<Action<FFOptions>> _configurations;

		private readonly FFMpegArguments _ffMpegArguments;

		private Action<double>? _onPercentageProgress;

		private Action<TimeSpan>? _onTimeProgress;

		private Action<string>? _onOutput;

		private Action<string>? _onError;

		private TimeSpan? _totalTimespan;

		private FFMpegLogLevel? _logLevel;

		public string Arguments => _ffMpegArguments.Text;

		private event EventHandler<int> CancelEvent;

		internal FFMpegArgumentProcessor(FFMpegArguments ffMpegArguments)
		{
			_configurations = new List<Action<FFOptions>>();
			_ffMpegArguments = ffMpegArguments;
		}

		public FFMpegArgumentProcessor NotifyOnProgress(Action<double> onPercentageProgress, TimeSpan totalTimeSpan)
		{
			_totalTimespan = totalTimeSpan;
			_onPercentageProgress = onPercentageProgress;
			return this;
		}

		public FFMpegArgumentProcessor NotifyOnProgress(Action<TimeSpan> onTimeProgress)
		{
			_onTimeProgress = onTimeProgress;
			return this;
		}

		public FFMpegArgumentProcessor NotifyOnOutput(Action<string> onOutput)
		{
			_onOutput = onOutput;
			return this;
		}

		public FFMpegArgumentProcessor NotifyOnError(Action<string> onError)
		{
			_onError = onError;
			return this;
		}

		public FFMpegArgumentProcessor CancellableThrough(out Action cancel, int timeout = 0)
		{
			cancel = delegate
			{
				this.CancelEvent?.Invoke(this, timeout);
			};
			return this;
		}

		public FFMpegArgumentProcessor CancellableThrough(CancellationToken token, int timeout = 0)
		{
			token.Register(delegate
			{
				this.CancelEvent?.Invoke(this, timeout);
			});
			return this;
		}

		public FFMpegArgumentProcessor Configure(Action<FFOptions> configureOptions)
		{
			_configurations.Add(configureOptions);
			return this;
		}

		public FFMpegArgumentProcessor WithLogLevel(FFMpegLogLevel logLevel)
		{
			_logLevel = logLevel;
			return this;
		}

		public bool ProcessSynchronously(bool throwOnError = true, FFOptions? ffMpegOptions = null)
		{
			FFOptions configuredOptions = GetConfiguredOptions(ffMpegOptions);
			CancellationTokenSource cancellationTokenSource;
			ProcessArguments processArguments = PrepareProcessArguments(configuredOptions, out cancellationTokenSource);
			IProcessResult val = null;
			try
			{
				val = Process(processArguments, cancellationTokenSource).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult();
			}
			catch (OperationCanceledException)
			{
				if (throwOnError)
				{
					throw;
				}
			}
			return HandleCompletion(throwOnError, (val != null) ? val.ExitCode : (-1), ((val != null) ? val.ErrorData : null) ?? Array.Empty<string>());
		}

		public async Task<bool> ProcessAsynchronously(bool throwOnError = true, FFOptions? ffMpegOptions = null)
		{
			FFOptions configuredOptions = GetConfiguredOptions(ffMpegOptions);
			CancellationTokenSource cancellationTokenSource;
			ProcessArguments processArguments = PrepareProcessArguments(configuredOptions, out cancellationTokenSource);
			IProcessResult processResult = null;
			try
			{
				processResult = await Process(processArguments, cancellationTokenSource).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (OperationCanceledException)
			{
				if (throwOnError)
				{
					throw;
				}
			}
			FFMpegArgumentProcessor fFMpegArgumentProcessor = this;
			IProcessResult obj = processResult;
			int exitCode = ((obj != null) ? obj.ExitCode : (-1));
			IProcessResult obj2 = processResult;
			return fFMpegArgumentProcessor.HandleCompletion(throwOnError, exitCode, ((obj2 != null) ? obj2.ErrorData : null) ?? Array.Empty<string>());
		}

		private async Task<IProcessResult> Process(ProcessArguments processArguments, CancellationTokenSource cancellationTokenSource)
		{
			CancellationTokenSource cancellationTokenSource2 = cancellationTokenSource;
			IProcessResult processResult = null;
			_ffMpegArguments.Pre();
			IProcessInstance instance = processArguments.Start();
			bool cancelled;
			try
			{
				cancelled = false;
				CancelEvent += OnCancelEvent;
				try
				{
					await Task.WhenAll(instance.WaitForExitAsync(default(CancellationToken)).ContinueWith(delegate(Task<IProcessResult> t)
					{
						processResult = t.Result;
						cancellationTokenSource2.Cancel();
						_ffMpegArguments.Post();
					}), _ffMpegArguments.During(cancellationTokenSource2.Token)).ConfigureAwait(continueOnCapturedContext: false);
					if (cancelled)
					{
						throw new OperationCanceledException("ffmpeg processing was cancelled");
					}
					return processResult;
				}
				finally
				{
					CancelEvent -= OnCancelEvent;
				}
			}
			finally
			{
				if (instance != null)
				{
					((IDisposable)instance).Dispose();
				}
			}
			void OnCancelEvent(object sender, int timeout)
			{
				cancelled = true;
				instance.SendInput("q");
				if (!cancellationTokenSource2.Token.WaitHandle.WaitOne(timeout, exitContext: true))
				{
					cancellationTokenSource2.Cancel();
					instance.Kill();
				}
			}
		}

		private bool HandleCompletion(bool throwOnError, int exitCode, IReadOnlyList<string> errorData)
		{
			if (throwOnError && exitCode != 0)
			{
				throw new FFMpegException(FFMpegExceptionType.Process, string.Format("ffmpeg exited with non-zero exit-code ({0} - {1})", exitCode, string.Join("\n", errorData)), null, string.Join("\n", errorData));
			}
			_onPercentageProgress?.Invoke(100.0);
			if (_totalTimespan.HasValue)
			{
				_onTimeProgress?.Invoke(_totalTimespan.Value);
			}
			return exitCode == 0;
		}

		internal FFOptions GetConfiguredOptions(FFOptions? ffOptions)
		{
			FFOptions fFOptions = ffOptions ?? GlobalFFOptions.Current.Clone();
			foreach (Action<FFOptions> configuration in _configurations)
			{
				configuration(fFOptions);
			}
			return fFOptions;
		}

		private ProcessArguments PrepareProcessArguments(FFOptions ffOptions, out CancellationTokenSource cancellationTokenSource)
		{
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			FFMpegHelper.RootExceptionCheck();
			FFMpegHelper.VerifyFFMpegExists(ffOptions);
			string text = _ffMpegArguments.Text;
			if (!_logLevel.HasValue)
			{
				_logLevel = ffOptions.LogLevel;
			}
			if (_logLevel.HasValue)
			{
				string text2 = _logLevel.ToString().ToLower();
				text = text + " -v " + text2;
			}
			ProcessArguments val = new ProcessArguments(new ProcessStartInfo
			{
				FileName = GlobalFFOptions.GetFFMpegBinaryPath(ffOptions),
				Arguments = text,
				StandardOutputEncoding = ffOptions.Encoding,
				StandardErrorEncoding = ffOptions.Encoding,
				WorkingDirectory = ffOptions.WorkingDirectory
			});
			cancellationTokenSource = new CancellationTokenSource();
			if (_onOutput != null)
			{
				val.OutputDataReceived += OutputData;
			}
			if (_onError != null || _onTimeProgress != null || (_onPercentageProgress != null && _totalTimespan.HasValue))
			{
				val.ErrorDataReceived += ErrorData;
			}
			return val;
		}

		private void ErrorData(object sender, string msg)
		{
			_onError?.Invoke(msg);
			Match match = ProgressRegex.Match(msg);
			if (match.Success)
			{
				TimeSpan obj = TimeSpan.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
				_onTimeProgress?.Invoke(obj);
				if (_onPercentageProgress != null && _totalTimespan.HasValue)
				{
					double obj2 = Math.Round(obj.TotalSeconds / _totalTimespan.Value.TotalSeconds * 100.0, 2);
					_onPercentageProgress(obj2);
				}
			}
		}

		private void OutputData(object sender, string msg)
		{
			_onOutput?.Invoke(msg);
		}
	}
	public sealed class FFMpegArguments : FFMpegArgumentsBase
	{
		private readonly FFMpegGlobalArguments _globalArguments = new FFMpegGlobalArguments();

		public string Text => GetText();

		private FFMpegArguments()
		{
		}

		private string GetText()
		{
			IArgument[] allArguments = _globalArguments.Arguments.Concat(Arguments).ToArray();
			return string.Join(" ", allArguments.Select((IArgument arg) => (!(arg is IDynamicArgument dynamicArgument)) ? arg.Text : dynamicArgument.GetText(allArguments)));
		}

		public static FFMpegArguments FromConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return new FFMpegArguments().WithInput(new ConcatArgument(filePaths), addArguments);
		}

		public static FFMpegArguments FromDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return new FFMpegArguments().WithInput(new DemuxConcatArgument(filePaths), addArguments);
		}

		public static FFMpegArguments FromFileInput(string filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return new FFMpegArguments().WithInput(new InputArgument(verifyExists, filePath), addArguments);
		}

		public static FFMpegArguments FromFileInput(FileInfo fileInfo, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return new FFMpegArguments().WithInput(new InputArgument(fileInfo.FullName, verifyExists: false), addArguments);
		}

		public static FFMpegArguments FromUrlInput(Uri uri, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return new FFMpegArguments().WithInput(new InputArgument(uri.AbsoluteUri, verifyExists: false), addArguments);
		}

		public static FFMpegArguments FromDeviceInput(string device, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return new FFMpegArguments().WithInput(new InputDeviceArgument(device), addArguments);
		}

		public static FFMpegArguments FromPipeInput(IPipeSource sourcePipe, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return new FFMpegArguments().WithInput(new InputPipeArgument(sourcePipe), addArguments);
		}

		public FFMpegArguments WithGlobalOptions(Action<FFMpegGlobalArguments> configureOptions)
		{
			configureOptions(_globalArguments);
			return this;
		}

		public FFMpegArguments AddConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new ConcatArgument(filePaths), addArguments);
		}

		public FFMpegArguments AddDemuxConcatInput(IEnumerable<string> filePaths, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new DemuxConcatArgument(filePaths), addArguments);
		}

		public FFMpegArguments AddFileInput(string filePath, bool verifyExists = true, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new InputArgument(verifyExists, filePath), addArguments);
		}

		public FFMpegArguments AddFileInput(FileInfo fileInfo, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new InputArgument(fileInfo.FullName, verifyExists: false), addArguments);
		}

		public FFMpegArguments AddUrlInput(Uri uri, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new InputArgument(uri.AbsoluteUri, verifyExists: false), addArguments);
		}

		public FFMpegArguments AddDeviceInput(string device, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new InputDeviceArgument(device), addArguments);
		}

		public FFMpegArguments AddPipeInput(IPipeSource sourcePipe, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new InputPipeArgument(sourcePipe), addArguments);
		}

		public FFMpegArguments AddMetaData(string content, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new MetaDataArgument(content), addArguments);
		}

		public FFMpegArguments AddMetaData(IReadOnlyMetaData metaData, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new MetaDataArgument(MetaDataSerializer.Instance.Serialize(metaData)), addArguments);
		}

		public FFMpegArguments MapMetaData(int? inputIndex = null, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return WithInput(new MapMetadataArgument(inputIndex), addArguments);
		}

		private FFMpegArguments WithInput(IInputArgument inputArgument, Action<FFMpegArgumentOptions>? addArguments)
		{
			FFMpegArgumentOptions fFMpegArgumentOptions = new FFMpegArgumentOptions();
			addArguments?.Invoke(fFMpegArgumentOptions);
			Arguments.AddRange(fFMpegArgumentOptions.Arguments);
			Arguments.Add(inputArgument);
			return this;
		}

		public FFMpegArgumentProcessor OutputToFile(string file, bool overwrite = true, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return ToProcessor(new OutputArgument(file, overwrite), addArguments);
		}

		public FFMpegArgumentProcessor OutputToUrl(string uri, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return ToProcessor(new OutputUrlArgument(uri), addArguments);
		}

		public FFMpegArgumentProcessor OutputToUrl(Uri uri, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return ToProcessor(new OutputUrlArgument(uri.ToString()), addArguments);
		}

		public FFMpegArgumentProcessor OutputToPipe(IPipeSink reader, Action<FFMpegArgumentOptions>? addArguments = null)
		{
			return ToProcessor(new OutputPipeArgument(reader), addArguments);
		}

		private FFMpegArgumentProcessor ToProcessor(IOutputArgument argument, Action<FFMpegArgumentOptions>? addArguments)
		{
			FFMpegArgumentOptions fFMpegArgumentOptions = new FFMpegArgumentOptions();
			addArguments?.Invoke(fFMpegArgumentOptions);
			Arguments.AddRange(fFMpegArgumentOptions.Arguments);
			Arguments.Add(argument);
			return new FFMpegArgumentProcessor(this);
		}

		internal void Pre()
		{
			foreach (IInputOutputArgument item in Arguments.OfType<IInputOutputArgument>())
			{
				item.Pre();
			}
		}

		internal async Task During(CancellationToken cancellationToken = default(CancellationToken))
		{
			await Task.WhenAll(from io in Arguments.OfType<IInputOutputArgument>()
				select io.During(cancellationToken)).ConfigureAwait(continueOnCapturedContext: false);
		}

		internal void Post()
		{
			foreach (IInputOutputArgument item in Arguments.OfType<IInputOutputArgument>())
			{
				item.Post();
			}
		}
	}
	public abstract class FFMpegArgumentsBase
	{
		internal readonly List<IArgument> Arguments = new List<IArgument>();
	}
	internal static class FFMpegCache
	{
		private static readonly object _syncObject = new object();

		private static Dictionary<string, PixelFormat>? _pixelFormats;

		private static Dictionary<string, Codec>? _codecs;

		private static Dictionary<string, ContainerFormat>? _containers;

		public static IReadOnlyDictionary<string, PixelFormat> PixelFormats
		{
			get
			{
				if (_pixelFormats == null)
				{
					lock (_syncObject)
					{
						if (_pixelFormats == null)
						{
							_pixelFormats = FFMpeg.GetPixelFormatsInternal().ToDictionary((PixelFormat x) => x.Name);
						}
					}
				}
				return _pixelFormats;
			}
		}

		public static IReadOnlyDictionary<string, Codec> Codecs
		{
			get
			{
				if (_codecs == null)
				{
					lock (_syncObject)
					{
						if (_codecs == null)
						{
							_codecs = FFMpeg.GetCodecsInternal();
						}
					}
				}
				return _codecs;
			}
		}

		public static IReadOnlyDictionary<string, ContainerFormat> ContainerFormats
		{
			get
			{
				if (_containers == null)
				{
					lock (_syncObject)
					{
						if (_containers == null)
						{
							_containers = FFMpeg.GetContainersFormatsInternal().ToDictionary((ContainerFormat x) => x.Name);
						}
					}
				}
				return _containers;
			}
		}
	}
	public sealed class FFMpegGlobalArguments : FFMpegArgumentsBase
	{
		internal FFMpegGlobalArguments()
		{
		}

		public FFMpegGlobalArguments WithVerbosityLevel(VerbosityLevel verbosityLevel = VerbosityLevel.Error)
		{
			return WithOption(new VerbosityLevelArgument(verbosityLevel));
		}

		private FFMpegGlobalArguments WithOption(IArgument argument)
		{
			Arguments.Add(argument);
			return this;
		}
	}
	public static class SnapshotArgumentBuilder
	{
		public static (FFMpegArguments, Action<FFMpegArgumentOptions> outputOptions) BuildSnapshotArguments(string input, IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null, int? streamIndex = null, int inputFileIndex = 0)
		{
			TimeSpan valueOrDefault = captureTime.GetValueOrDefault();
			if (!captureTime.HasValue)
			{
				valueOrDefault = TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3.0);
				captureTime = valueOrDefault;
			}
			size = PrepareSnapshotSize(source, size);
			int valueOrDefault2 = streamIndex.GetValueOrDefault();
			if (!streamIndex.HasValue)
			{
				valueOrDefault2 = source.PrimaryVideoStream?.Index ?? source.VideoStreams.FirstOrDefault()?.Index ?? 0;
				streamIndex = valueOrDefault2;
			}
			return (FFMpegArguments.FromFileInput(input, verifyExists: false, delegate(FFMpegArgumentOptions options)
			{
				options.Seek(captureTime);
			}), delegate(FFMpegArgumentOptions options)
			{
				options.SelectStream(streamIndex.Value, inputFileIndex).WithVideoCodec(VideoCodec.Png).WithFrameOutputCount(1)
					.Resize(size);
			});
		}

		public static (FFMpegArguments, Action<FFMpegArgumentOptions> outputOptions) BuildGifSnapshotArguments(string input, IMediaAnalysis source, Size? size = null, TimeSpan? captureTime = null, TimeSpan? duration = null, int? streamIndex = null, int fps = 12)
		{
			Size size2 = new Size(480, -1);
			TimeSpan valueOrDefault = captureTime.GetValueOrDefault();
			if (!captureTime.HasValue)
			{
				valueOrDefault = TimeSpan.FromSeconds(source.Duration.TotalSeconds / 3.0);
				captureTime = valueOrDefault;
			}
			size = PrepareSnapshotSize(source, size) ?? size2;
			int valueOrDefault2 = streamIndex.GetValueOrDefault();
			if (!streamIndex.HasValue)
			{
				valueOrDefault2 = source.PrimaryVideoStream?.Index ?? source.VideoStreams.FirstOrDefault()?.Index ?? 0;
				streamIndex = valueOrDefault2;
			}
			return (FFMpegArguments.FromFileInput(input, verifyExists: false, delegate(FFMpegArgumentOptions options)
			{
				options.Seek(captureTime).WithDuration(duration);
			}), delegate(FFMpegArgumentOptions options)
			{
				options.WithGifPaletteArgument(streamIndex.Value, size, fps);
			});
		}

		private static Size? PrepareSnapshotSize(IMediaAnalysis source, Size? wantedSize)
		{
			if (!wantedSize.HasValue || (wantedSize.Value.Height <= 0 && wantedSize.Value.Width <= 0) || source.PrimaryVideoStream == null)
			{
				return null;
			}
			Size size = new Size(source.PrimaryVideoStream.Width, source.PrimaryVideoStream.Height);
			if (source.PrimaryVideoStream.Rotation == 90 || source.PrimaryVideoStream.Rotation == 180)
			{
				size = new Size(source.PrimaryVideoStream.Height, source.PrimaryVideoStream.Width);
			}
			if (wantedSize.Value.Width != size.Width || wantedSize.Value.Height != size.Height)
			{
				if (wantedSize.Value.Width <= 0 && wantedSize.Value.Height > 0)
				{
					double num = (double)wantedSize.Value.Height / (double)size.Height;
					return new Size((int)((double)size.Width * num), (int)((double)size.Height * num));
				}
				if (wantedSize.Value.Height <= 0 && wantedSize.Value.Width > 0)
				{
					double num2 = (double)wantedSize.Value.Width / (double)size.Width;
					return new Size((int)((double)size.Width * num2), (int)((double)size.Height * num2));
				}
				return wantedSize;
			}
			return null;
		}
	}
	public class FFOptions : ICloneable
	{
		public string WorkingDirectory { get; set; } = string.Empty;


		public string BinaryFolder { get; set; } = string.Empty;


		public string TemporaryFilesFolder { get; set; } = Path.GetTempPath();


		public Encoding Encoding { get; set; } = System.Text.Encoding.Default;


		public FFMpegLogLevel? LogLevel { get; set; }

		public Dictionary<string, string> ExtensionOverrides { get; set; } = new Dictionary<string, string> { { "mpegts", ".ts" } };


		public bool UseCache { get; set; } = true;


		object ICloneable.Clone()
		{
			return Clone();
		}

		public FFOptions Clone()
		{
			return (FFOptions)MemberwiseClone();
		}
	}
	public class AudioStream : MediaStream
	{
		public int Channels { get; set; }

		public string ChannelLayout { get; set; }

		public int SampleRateHz { get; set; }

		public string Profile { get; set; }
	}
	public static class FFProbe
	{
		public static IMediaAnalysis Analyse(string filePath, FFOptions? ffOptions = null)
		{
			ThrowIfInputFileDoesNotExist(filePath);
			IProcessResult obj = PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExit();
			ThrowIfExitCodeNotZero(obj);
			return ParseOutput(obj);
		}

		public static FFProbeFrames GetFrames(string filePath, FFOptions? ffOptions = null)
		{
			ThrowIfInputFileDoesNotExist(filePath);
			IProcessResult obj = PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExit();
			ThrowIfExitCodeNotZero(obj);
			return ParseFramesOutput(obj);
		}

		public static FFProbePackets GetPackets(string filePath, FFOptions? ffOptions = null)
		{
			ThrowIfInputFileDoesNotExist(filePath);
			IProcessResult obj = PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExit();
			ThrowIfExitCodeNotZero(obj);
			return ParsePacketsOutput(obj);
		}

		public static IMediaAnalysis Analyse(Uri uri, FFOptions? ffOptions = null)
		{
			IProcessResult obj = PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExit();
			ThrowIfExitCodeNotZero(obj);
			return ParseOutput(obj);
		}

		public static IMediaAnalysis Analyse(Stream stream, FFOptions? ffOptions = null)
		{
			InputPipeArgument inputPipeArgument = new InputPipeArgument(new StreamPipeSource(stream));
			ProcessArguments processArguments = PrepareStreamAnalysisInstance(inputPipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current);
			inputPipeArgument.Pre();
			Task<IProcessResult> task = processArguments.StartAndWaitForExitAsync();
			try
			{
				inputPipeArgument.During().ConfigureAwait(continueOnCapturedContext: false).GetAwaiter()
					.GetResult();
			}
			catch (IOException)
			{
			}
			finally
			{
				inputPipeArgument.Post();
			}
			IProcessResult result = task.ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult();
			ThrowIfExitCodeNotZero(result);
			return ParseOutput(result);
		}

		public static async Task<IMediaAnalysis> AnalyseAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			ThrowIfInputFileDoesNotExist(filePath);
			IProcessResult obj = await PrepareStreamAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			ThrowIfExitCodeNotZero(obj);
			return ParseOutput(obj);
		}

		public static FFProbeFrames GetFrames(Uri uri, FFOptions? ffOptions = null)
		{
			IProcessResult obj = PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExit();
			ThrowIfExitCodeNotZero(obj);
			return ParseFramesOutput(obj);
		}

		public static async Task<FFProbeFrames> GetFramesAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			ThrowIfInputFileDoesNotExist(filePath);
			return ParseFramesOutput(await PrepareFrameAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false));
		}

		public static async Task<FFProbePackets> GetPacketsAsync(string filePath, FFOptions? ffOptions = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			ThrowIfInputFileDoesNotExist(filePath);
			return ParsePacketsOutput(await PreparePacketAnalysisInstance(filePath, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false));
		}

		public static async Task<IMediaAnalysis> AnalyseAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			IProcessResult obj = await PrepareStreamAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			ThrowIfExitCodeNotZero(obj);
			return ParseOutput(obj);
		}

		public static async Task<IMediaAnalysis> AnalyseAsync(Stream stream, FFOptions? ffOptions = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			StreamPipeSource writer = new StreamPipeSource(stream);
			InputPipeArgument pipeArgument = new InputPipeArgument(writer);
			ProcessArguments processArguments = PrepareStreamAnalysisInstance(pipeArgument.PipePath, ffOptions ?? GlobalFFOptions.Current);
			pipeArgument.Pre();
			Task<IProcessResult> task = processArguments.StartAndWaitForExitAsync(cancellationToken);
			try
			{
				await pipeArgument.During(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			catch (IOException)
			{
			}
			finally
			{
				pipeArgument.Post();
			}
			IProcessResult obj = await task.ConfigureAwait(continueOnCapturedContext: false);
			ThrowIfExitCodeNotZero(obj);
			pipeArgument.Post();
			return ParseOutput(obj);
		}

		public static async Task<FFProbeFrames> GetFramesAsync(Uri uri, FFOptions? ffOptions = null, CancellationToken cancellationToken = default(CancellationToken))
		{
			return ParseFramesOutput(await PrepareFrameAnalysisInstance(uri.AbsoluteUri, ffOptions ?? GlobalFFOptions.Current).StartAndWaitForExitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false));
		}

		private static IMediaAnalysis ParseOutput(IProcessResult instance)
		{
			FFProbeAnalysis? fFProbeAnalysis = JsonSerializer.Deserialize<FFProbeAnalysis>(string.Join(string.Empty, instance.OutputData), new JsonSerializerOptions
			{
				PropertyNameCaseInsensitive = true
			});
			if (fFProbeAnalysis?.Format == null)
			{
				throw new FormatNullException();
			}
			fFProbeAnalysis.ErrorData = instance.ErrorData;
			return new MediaAnalysis(fFProbeAnalysis);
		}

		private static FFProbeFrames ParseFramesOutput(IProcessResult instance)
		{
			return JsonSerializer.Deserialize<FFProbeFrames>(string.Join(string.Empty, instance.OutputData), new JsonSerializerOptions
			{
				PropertyNameCaseInsensitive = true,
				NumberHandling = (JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)
			});
		}

		private static FFProbePackets ParsePacketsOutput(IProcessResult instance)
		{
			return JsonSerializer.Deserialize<FFProbePackets>(string.Join(string.Empty, instance.OutputData), new JsonSerializerOptions
			{
				PropertyNameCaseInsensitive = true,
				NumberHandling = (JsonNumberHandling.AllowReadingFromString | JsonNumberHandling.WriteAsString)
			});
		}

		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)
			{
				string message = string.Format("ffprobe exited with non-zero exit-code ({0} - {1})", 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)
		{
			return PrepareInstance("-loglevel error -print_format json -show_format -sexagesimal -show_streams \"" + filePath + "\"", ffOptions);
		}

		private static ProcessArguments PrepareFrameAnalysisInstance(string filePath, FFOptions ffOptions)
		{
			return PrepareInstance("-loglevel error -print_format json -show_frames -v quiet -sexagesimal \"" + filePath + "\"", ffOptions);
		}

		private static ProcessArguments PreparePacketAnalysisInstance(string filePath, FFOptions ffOptions)
		{
			return PrepareInstance("-loglevel error -print_format json -show_packets -v quiet -sexagesimal \"" + filePath + "\"", ffOptions);
		}

		private static ProcessArguments PrepareInstance(string arguments, FFOptions ffOptions)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			FFProbeHelper.RootExceptionCheck();
			FFProbeHelper.VerifyFFProbeExists(ffOptions);
			return new ProcessArguments(new ProcessStartInfo(GlobalFFOptions.GetFFProbeBinaryPath(ffOptions), arguments)
			{
				StandardOutputEncoding = ffOptions.Encoding,
				StandardErrorEncoding = ffOptions.Encoding,
				WorkingDirectory = ffOptions.WorkingDirectory
			});
		}
	}
	public class FFProbeAnalysis
	{
		[JsonPropertyName("streams")]
		public List<FFProbeStream> Streams { get; set; }

		[JsonPropertyName("format")]
		public Format Format { get; set; }

		[JsonIgnore]
		public IReadOnlyList<string> ErrorData { get; set; } = new List<string>();

	}
	public class FFProbeStream : ITagsContainer, IDispositionContainer
	{
		[JsonPropertyName("index")]
		public int Index { get; set; }

		[JsonPropertyName("avg_frame_rate")]
		public string AvgFrameRate { get; set; }

		[JsonPropertyName("bits_per_raw_sample")]
		public string BitsPerRawSample { get; set; }

		[JsonPropertyName("bits_per_sample")]
		public int BitsPerSample { get; set; }

		[JsonPropertyName("bit_rate")]
		public string BitRate { get; set; }

		[JsonPropertyName("channels")]
		public int? Channels { get; set; }

		[JsonPropertyName("channel_layout")]
		public string ChannelLayout { get; set; }

		[JsonPropertyName("codec_type")]
		public string CodecType { get; set; }

		[JsonPropertyName("codec_name")]
		public string CodecName { get; set; }

		[JsonPropertyName("codec_long_name")]
		public string CodecLongName { get; set; }

		[JsonPropertyName("codec_tag")]
		public string CodecTag { get; set; }

		[JsonPropertyName("codec_tag_string")]
		public string CodecTagString { get; set; }

		[JsonPropertyName("display_aspect_ratio")]
		public string DisplayAspectRatio { get; set; }

		[JsonPropertyName("sample_aspect_ratio")]
		public string SampleAspectRatio { get; set; }

		[JsonPropertyName("start_time")]
		public string StartTime { get; set; }

		[JsonPropertyName("duration")]
		public string Duration { get; set; }

		[JsonPropertyName("profile")]
		public string Profile { get; set; }

		[JsonPropertyName("width")]
		public int? Width { get; set; }

		[JsonPropertyName("height")]
		public int? Height { get; set; }

		[JsonPropertyName("r_frame_rate")]
		public string FrameRate { get; set; }

		[JsonPropertyName("pix_fmt")]
		public string PixelFormat { get; set; }

		[JsonPropertyName("sample_rate")]
		public string SampleRate { get; set; }

		[JsonPropertyName("disposition")]
		public Dictionary<string, int> Disposition { get; set; }

		[JsonPropertyName("tags")]
		public Dictionary<string, string> Tags { get; set; }

		[JsonPropertyName("side_data_list")]
		public List<Dictionary<string, JsonValue>> SideData { get; set; }
	}
	public class Format : ITagsContainer
	{
		[JsonPropertyName("filename")]
		public string Filename { get; set; }

		[JsonPropertyName("nb_streams")]
		public int NbStreams { get; set; }

		[JsonPropertyName("nb_programs")]
		public int NbPrograms { get; set; }

		[JsonPropertyName("format_name")]
		public string FormatName { get; set; }

		[JsonPropertyName("format_long_name")]
		public string FormatLongName { get; set; }

		[JsonPropertyName("start_time")]
		public string StartTime { get; set; }

		[JsonPropertyName("duration")]
		public string Duration { get; set; }

		[JsonPropertyName("size")]
		public string Size { get; set; }

		[JsonPropertyName("bit_rate")]
		public string? BitRate { get; set; }

		[JsonPropertyName("probe_score")]
		public int ProbeScore { get; set; }

		[JsonPropertyName("tags")]
		public Dictionary<string, string> Tags { get; set; }
	}
	public interface IDispositionContainer
	{
		Dictionary<string, int> Disposition { get; set; }
	}
	public interface ITagsContainer
	{
		Dictionary<string, string> Tags { get; set; }
	}
	public static class TagExtensions
	{
		private static string? TryGetTagValue(ITagsContainer tagsContainer, string key)
		{
			if (tagsContainer.Tags != null && tagsContainer.Tags.TryGetValue(key, out string value))
			{
				return value;
			}
			return null;
		}

		public static string? GetLanguage(this ITagsContainer tagsContainer)
		{
			return TryGetTagValue(tagsContainer, "language");
		}

		public static string? GetCreationTime(this ITagsContainer tagsContainer)
		{
			return TryGetTagValue(tagsContainer, "creation_time ");
		}

		public static string? GetRotate(this ITagsContainer tagsContainer)
		{
			return TryGetTagValue(tagsContainer, "rotate");
		}

		public static string? GetDuration(this ITagsContainer tagsContainer)
		{
			return TryGetTagValue(tagsContainer, "duration");
		}
	}
	public static class DispositionExtensions
	{
		private static int? TryGetDispositionValue(IDispositionContainer dispositionContainer, string key)
		{
			if (dispositionContainer.Disposition != null && dispositionContainer.Disposition.TryGetValue(key, out var value))
			{
				return value;
			}
			return null;
		}

		public static int? GetDefault(this IDispositionContainer tagsContainer)
		{
			return TryGetDispositionValue(tagsContainer, "default");
		}

		public static int? GetForced(this IDispositionContainer tagsContainer)
		{
			return TryGetDispositionValue(tagsContainer, "forced");
		}
	}
	public class FFProbeFrameAnalysis
	{
		[JsonPropertyName("media_type")]
		public string MediaType { get; set; }

		[JsonPropertyName("stream_index")]
		public int StreamIndex { get; set; }

		[JsonPropertyName("key_frame")]
		public int KeyFrame { get; set; }

		[JsonPropertyName("pkt_pts")]
		public long PacketPts { get; set; }

		[JsonPropertyName("pkt_pts_time")]
		public string PacketPtsTime { get; set; }

		[JsonPropertyName("pkt_dts")]
		public long PacketDts { get; set; }

		[JsonPropertyName("pkt_dts_time")]
		public string PacketDtsTime { get; set; }

		[JsonPropertyName("best_effort_timestamp")]
		public long BestEffortTimestamp { get; set; }

		[JsonPropertyName("best_effort_timestamp_time")]
		public string BestEffortTimestampTime { get; set; }

		[JsonPropertyName("pkt_duration")]
		public int PacketDuration { get; set; }

		[JsonPropertyName("pkt_duration_time")]
		public string PacketDurationTime { get; set; }

		[JsonPropertyName("pkt_pos")]
		public long PacketPos { get; set; }

		[JsonPropertyName("pkt_size")]
		public int PacketSize { get; set; }

		[JsonPropertyName("width")]
		public long Width { get; set; }

		[JsonPropertyName("height")]
		public long Height { get; set; }

		[JsonPropertyName("pix_fmt")]
		public string PixelFormat { get; set; }

		[JsonPropertyName("pict_type")]
		public string PictureType { get; set; }

		[JsonPropertyName("coded_picture_number")]
		public long CodedPictureNumber { get; set; }

		[JsonPropertyName("display_picture_number")]
		public long DisplayPictureNumber { get; set; }

		[JsonPropertyName("interlaced_frame")]
		public int InterlacedFrame { get; set; }

		[JsonPropertyName("top_field_first")]
		public int TopFieldFirst { get; set; }

		[JsonPropertyName("repeat_pict")]
		public int RepeatPicture { get; set; }

		[JsonPropertyName("chroma_location")]
		public string ChromaLocation { get; set; }
	}
	public class FFProbeFrames
	{
		[JsonPropertyName("frames")]
		public List<FFProbeFrameAnalysis> Frames { get; set; }
	}
	public interface IMediaAnalysis
	{
		TimeSpan Duration { get; }

		MediaFormat Format { get; }

		AudioStream? PrimaryAudioStream { get; }

		VideoStream? PrimaryVideoStream { get; }

		SubtitleStream? PrimarySubtitleStream { get; }

		List<VideoStream> VideoStreams { get; }

		List<AudioStream> AudioStreams { get; }

		List<SubtitleStream> SubtitleStreams { get; }

		IReadOnlyList<string> ErrorData { get; }
	}
	internal class MediaAnalysis : IMediaAnalysis
	{
		public TimeSpan Duration => new TimeSpan[3]
		{
			Format.Duration,
			PrimaryVideoStream?.Duration ?? TimeSpan.Zero,
			PrimaryAudioStream?.Duration ?? TimeSpan.Zero
		}.Max();

		public MediaFormat Format { get; }

		public AudioStream? PrimaryAudioStream => AudioStreams.OrderBy((AudioStream stream) => stream.Index).FirstOrDefault();

		public VideoStream? PrimaryVideoStream => VideoStreams.OrderBy((VideoStream stream) => stream.Index).FirstOrDefault();

		public SubtitleStream? PrimarySubtitleStream => SubtitleStreams.OrderBy((SubtitleStream stream) => stream.Index).FirstOrDefault();

		public List<VideoStream> VideoStreams { get; }

		public List<AudioStream> AudioStreams { get; }

		public List<SubtitleStream> SubtitleStreams { get; }

		public IReadOnlyList<string> ErrorData { get; }

		internal MediaAnalysis(FFProbeAnalysis analysis)
		{
			Format = ParseFormat(analysis.Format);
			VideoStreams = analysis.Streams.Where((FFProbeStream stream) => stream.CodecType == "video").Select(ParseVideoStream).ToList();
			AudioStreams = analysis.Streams.Where((FFProbeStream stream) => stream.CodecType == "audio").Select(ParseAudioStream).ToList();
			SubtitleStreams = analysis.Streams.Where((FFProbeStream stream) => stream.CodecType == "subtitle").Select(ParseSubtitleStream).ToList();
			ErrorData = analysis.ErrorData;
		}

		private MediaFormat ParseFormat(Format analysisFormat)
		{
			return new MediaFormat
			{
				Duration = MediaAnalysisUtils.ParseDuration(analysisFormat.Duration),
				StartTime = MediaAnalysisUtils.ParseDuration(analysisFormat.StartTime),
				FormatName = analysisFormat.FormatName,
				FormatLongName = analysisFormat.FormatLongName,
				StreamCount = analysisFormat.NbStreams,
				ProbeScore = analysisFormat.ProbeScore,
				BitRate = long.Parse(analysisFormat.BitRate ?? "0"),
				Tags = analysisFormat.Tags.ToCaseInsensitive()
			};
		}

		private int? GetBitDepth(FFProbeStream stream)
		{
			int result;
			int num = (int.TryParse(stream.BitsPerRawSample, out result) ? result : stream.BitsPerSample);
			if (num != 0)
			{
				return num;
			}
			return null;
		}

		private VideoStream ParseVideoStream(FFProbeStream stream)
		{
			return new VideoStream
			{
				Index = stream.Index,
				AvgFrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.AvgFrameRate, '/')),
				BitRate = ((!string.IsNullOrEmpty(stream.BitRate)) ? MediaAnalysisUtils.ParseLongInvariant(stream.BitRate) : 0),
				BitsPerRawSample = ((!string.IsNullOrEmpty(stream.BitsPerRawSample)) ? MediaAnalysisUtils.ParseIntInvariant(stream.BitsPerRawSample) : 0),
				CodecName = stream.CodecName,
				CodecLongName = stream.CodecLongName,
				CodecTag = stream.CodecTag,
				CodecTagString = stream.CodecTagString,
				DisplayAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.DisplayAspectRatio, ':'),
				SampleAspectRatio = MediaAnalysisUtils.ParseRatioInt(stream.SampleAspectRatio, ':'),
				Duration = MediaAnalysisUtils.ParseDuration(stream.Duration),
				StartTime = MediaAnalysisUtils.ParseDuration(stream.StartTime),
				FrameRate = MediaAnalysisUtils.DivideRatio(MediaAnalysisUtils.ParseRatioDouble(stream.FrameRate, '/')),
				Height = stream.Height.GetValueOrDefault(),
				Width = stream.Width.GetValueOrDefault(),
				Profile = stream.Profile,
				PixelFormat = stream.PixelFormat,
				Rotation = MediaAnalysisUtils.ParseRotation(stream),
				Language = stream.GetLanguage(),
				Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition),
				Tags = stream.Tags.ToCaseInsensitive(),
				BitDepth = GetBitDepth(stream)
			};
		}

		private AudioStream ParseAudioStream(FFProbeStream stream)
		{
			return new AudioStream
			{
				Index = stream.Index,
				BitRate = ((!string.IsNullOrEmpty(stream.BitRate)) ? MediaAnalysisUtils.ParseLongInvariant(stream.BitRate) : 0),
				CodecName = stream.CodecName,
				CodecLongName = stream.CodecLongName,
				CodecTag = stream.CodecTag,
				CodecTagString = stream.CodecTagString,
				Channels = stream.Channels.GetValueOrDefault(),
				ChannelLayout = stream.ChannelLayout,
				Duration = MediaAnalysisUtils.ParseDuration(stream.Duration),
				StartTime = MediaAnalysisUtils.ParseDuration(stream.StartTime),
				SampleRateHz = ((!string.IsNullOrEmpty(stream.SampleRate)) ? MediaAnalysisUtils.ParseIntInvariant(stream.SampleRate) : 0),
				Profile = stream.Profile,
				Language = stream.GetLanguage(),
				Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition),
				Tags = stream.Tags.ToCaseInsensitive(),
				BitDepth = GetBitDepth(stream)
			};
		}

		private SubtitleStream ParseSubtitleStream(FFProbeStream stream)
		{
			return new SubtitleStream
			{
				Index = stream.Index,
				BitRate = ((!string.IsNullOrEmpty(stream.BitRate)) ? MediaAnalysisUtils.ParseLongInvariant(stream.BitRate) : 0),
				CodecName = stream.CodecName,
				CodecLongName = stream.CodecLongName,
				Duration = MediaAnalysisUtils.ParseDuration(stream.Duration),
				StartTime = MediaAnalysisUtils.ParseDuration(stream.StartTime),
				Language = stream.GetLanguage(),
				Disposition = MediaAnalysisUtils.FormatDisposition(stream.Disposition),
				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<string, string> ToCaseInsensitive(this Dictionary<string, string>? dictionary)
		{
			return dictionary?.ToDictionary<KeyValuePair<string, string>, string, string>((KeyValuePair<string, string> tag) => tag.Key, (KeyValuePair<string, string> tag) => tag.Value, StringComparer.OrdinalIgnoreCase) ?? new Dictionary<string, string>();
		}

		public static double DivideRatio((double, double) ratio)
		{
			return ratio.Item1 / ratio.Item2;
		}

		public static (int, int) ParseRatioInt(string input, char separator)
		{
			if (string.IsNullOrEmpty(input))
			{
				return (0, 0);
			}
			string[] array = input.Split(new char[1] { separator });
			return (ParseIntInvariant(array[0]), ParseIntInvariant(array[1]));
		}

		public static (double, double) ParseRatioDouble(string input, char separator)
		{
			if (string.IsNullOrEmpty(input))
			{
				return (0.0, 0.0);
			}
			string[] array = input.Split(new char[1] { separator });
			return ((array.Length != 0) ? ParseDoubleInvariant(array[0]) : 0.0, (array.Length > 1) ? ParseDoubleInvariant(array[1]) : 0.0);
		}

		public static double ParseDoubleInvariant(string line)
		{
			return double.Parse(line, NumberStyles.Any, CultureInfo.InvariantCulture);
		}

		public static int ParseIntInvariant(string line)
		{
			return int.Parse(line, NumberStyles.Any, CultureInfo.InvariantCulture);
		}

		public static long ParseLongInvariant(string line)
		{
			return long.Parse(line, NumberStyles.Any, CultureInfo.InvariantCulture);
		}

		public static TimeSpan ParseDuration(string duration)
		{
			if (!string.IsNullOrEmpty(duration))
			{
				Match match = DurationRegex.Match(duration);
				if (match.Success)
				{
					string text = match.Groups[4].Value;
					if (text.Length < 3)
					{
						text = text.PadRight(3, '0');
					}
					int hours = int.Parse(match.Groups[1].Value);
					int minutes = int.Parse(match.Groups[2].Value);
					int seconds = int.Parse(match.Groups[3].Value);
					int milliseconds = int.Parse(text);
					return new TimeSpan(0, hours, minutes, seconds, milliseconds);
				}
				return TimeSpan.Zero;
			}
			return TimeSpan.Zero;
		}

		public static int ParseRotation(FFProbeStream fFProbeStream)
		{
			JsonValue value2;
			Dictionary<string, JsonValue>? obj = fFProbeStream.SideData?.Find((Dictionary<string, JsonValue> item) => item.TryGetValue("side_data_type", out value2) && value2.ToString() == "Display Matrix");
			if (obj != null && obj.TryGetValue("rotation", out JsonValue value))
			{
				return (int)float.Parse(value.ToString());
			}
			return (int)float.Parse(fFProbeStream.GetRotate() ?? "0");
		}

		public static Dictionary<string, bool>? FormatDisposition(Dictionary<string, int>? disposition)
		{
			if (disposition == null)
			{
				return null;
			}
			Dictionary<string, bool> dictionary = new Dictionary<string, bool>(disposition.Count, StringComparer.Ordinal);
			foreach (KeyValuePair<string, int> item in disposition)
			{
				dictionary.Add(item.Key, ToBool(item.Value));
			}
			return dictionary;
			static bool ToBool(int value)
			{
				return value switch
				{
					0 => false, 
					1 => true, 
					_ => throw new ArgumentOutOfRangeException("value", $"Not expected disposition state value: {value}"), 
				};
			}
		}
	}
	public class MediaFormat
	{
		public TimeSpan Duration { get; set; }

		public TimeSpan StartTime { get; set; }

		public string FormatName { get; set; }

		public string FormatLongName { get; set; }

		public int StreamCount { get; set; }

		public double ProbeScore { get; set; }

		public double BitRate { get; set; }

		public Dictionary<string, string>? Tags { get; set; }
	}
	public abstract class MediaStream
	{
		public int Index { get; set; }

		public string CodecName { get; set; }

		public string CodecLongName { get; set; }

		public string CodecTagString { get; set; }

		public string CodecTag { get; set; }

		public long BitRate { get; set; }

		public TimeSpan StartTime { get; set; }

		public TimeSpan Duration { get; set; }

		public string? Language { get; set; }

		public Dictionary<string, bool>? Disposition { get; set; }

		public Dictionary<string, string>? Tags { get; set; }

		public int? BitDepth { get; set; }

		public Codec GetCodecInfo()
		{
			return FFMpeg.GetCodec(CodecName);
		}
	}
	public class FFProbePacketAnalysis
	{
		[JsonPropertyName("codec_type")]
		public string CodecType { get; set; }

		[JsonPropertyName("stream_index")]
		public int StreamIndex { get; set; }

		[JsonPropertyName("pts")]
		public long Pts { get; set; }

		[JsonPropertyName("pts_time")]
		public string PtsTime { get; set; }

		[JsonPropertyName("dts")]
		public long Dts { get; set; }

		[JsonPropertyName("dts_time")]
		public string DtsTime { get; set; }

		[JsonPropertyName("duration")]
		public int Duration { get; set; }

		[JsonPropertyName("duration_time")]
		public string DurationTime { get; set; }

		[JsonPropertyName("size")]
		public int Size { get; set; }

		[JsonPropertyName("pos")]
		public long Pos { get; set; }

		[JsonPropertyName("flags")]
		public string Flags { get; set; }
	}
	public class FFProbePackets
	{
		[JsonPropertyName("packets")]
		public List<FFProbePacketAnalysis> Packets { get; set; }
	}
	public static class ProcessArgumentsExtensions
	{
		public static IProcessResult StartAndWaitForExit(this ProcessArguments processArguments)
		{
			IProcessInstance val = processArguments.Start();
			try
			{
				return val.WaitForExit();
			}
			finally
			{
				((IDisposable)val)?.Dispose();
			}
		}

		public static async Task<IProcessResult> StartAndWaitForExitAsync(this ProcessArguments processArguments, CancellationToken cancellationToken = default(CancellationToken))
		{
			IProcessInstance instance = processArguments.Start();
			try
			{
				return await instance.WaitForExitAsync(cancellationToken);
			}
			finally
			{
				((IDisposable)instance)?.Dispose();
			}
		}
	}
	public class SubtitleStream : MediaStream
	{
	}
	public class VideoStream : MediaStream
	{
		public double AvgFrameRate { get; set; }

		public int BitsPerRawSample { get; set; }

		public (int Width, int Height) DisplayAspectRatio { get; set; }

		public (int Width, int Height) SampleAspectRatio { get; set; }

		public string Profile { get; set; }

		public int Width { get; set; }

		public int Height { get; set; }

		public double FrameRate { get; set; }

		public string PixelFormat { get; set; }

		public int Rotation { get; set; }

		public double AverageFrameRate { get; set; }

		public PixelFormat GetPixelFormatInfo()
		{
			return FFMpeg.GetPixelFormat(PixelFormat);
		}
	}
	public static class GlobalFFOptions
	{
		private const string ConfigFile = "ffmpeg.config.json";

		private static FFOptions? _current;

		public static FFOptions Current => _current ?? (_current = LoadFFOptions());

		public static void Configure(Action<FFOptions> optionsAction)
		{
			optionsAction(Current);
		}

		public static void Configure(FFOptions ffOptions)
		{
			_current = ffOptions ?? throw new ArgumentNullException("ffOptions");
		}

		public static string GetFFMpegBinaryPath(FFOptions? ffOptions = null)
		{
			return GetFFBinaryPath("FFMpeg", ffOptions ?? Current);
		}

		public static string GetFFProbeBinaryPath(FFOptions? ffOptions = null)
		{
			return GetFFBinaryPath("FFProbe", ffOptions ?? Current);
		}

		private static string GetFFBinaryPath(string name, FFOptions ffOptions)
		{
			string text = name.ToLowerInvariant();
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				text += ".exe";
			}
			string text2 = (Environment.Is64BitProcess ? "x64" : "x86");
			if (Directory.Exists(Path.Combine(ffOptions.BinaryFolder, text2)))
			{
				text = Path.Combine(text2, text);
			}
			return Path.Combine(ffOptions.BinaryFolder, text);
		}

		private static FFOptions LoadFFOptions()
		{
			if (!File.Exists("ffmpeg.config.json"))
			{
				return new FFOptions();
			}
			return JsonSerializer.Deserialize<FFOptions>(File.ReadAllText("ffmpeg.config.json"));
		}
	}
}
namespace FFMpegCore.Helpers
{
	public static class FFMpegHelper
	{
		private static bool _ffmpegVerified;

		public static void ConversionSizeExceptionCheck(IMediaAnalysis info)
		{
			ConversionSizeExceptionCheck(info.PrimaryVideoStream.Width, info.PrimaryVideoStream.Height);
		}

		public static void ConversionSizeExceptionCheck(int width, int height)
		{
			if (height % 2 != 0 || width % 2 != 0)
			{
				throw new ArgumentException("FFMpeg yuv420p encoding requires the width and height to be a multiple of 2!");
			}
		}

		public static void ExtensionExceptionCheck(string filename, string extension)
		{
			if (!extension.Equals(Path.GetExtension(filename), StringComparison.OrdinalIgnoreCase))
			{
				throw new FFMpegException(FFMpegExceptionType.File, "Invalid output file. File extension should be '" + extension + "' required.");
			}
		}

		public static void RootExceptionCheck()
		{
			if (GlobalFFOptions.Current.BinaryFolder == null)
			{
				throw new FFOptionsException("FFMpeg root is not configured in app config. Missing key 'BinaryFolder'.");
			}
		}

		public static void VerifyFFMpegExists(FFOptions ffMpegOptions)
		{
			if (!_ffmpegVerified)
			{
				_ffmpegVerified = Instance.Finish(GlobalFFOptions.GetFFMpegBinaryPath(ffMpegOptions), "-version", (EventHandler<string>)null, (EventHandler<string>)null).ExitCode == 0;
				if (!_ffmpegVerified)
				{
					throw new FFMpegException(FFMpegExceptionType.Operation, "ffmpeg was not found on your system");
				}
			}
		}
	}
	public static class FFProbeHelper
	{
		private static bool _ffprobeVerified;

		public static void RootExceptionCheck()
		{
			if (GlobalFFOptions.Current.BinaryFolder == null)
			{
				throw new FFOptionsException("FFProbe root is not configured in app config. Missing key 'BinaryFolder'.");
			}
		}

		public static void VerifyFFProbeExists(FFOptions ffMpegOptions)
		{
			if (!_ffprobeVerified)
			{
				_ffprobeVerified = Instance.Finish(GlobalFFOptions.GetFFProbeBinaryPath(ffMpegOptions), "-version", (EventHandler<string>)null, (EventHandler<string>)null).ExitCode == 0;
				if (!_ffprobeVerified)
				{
					throw new FFProbeException("ffprobe was not found on your system");
				}
			}
		}
	}
}
namespace FFMpegCore.Pipes
{
	public interface IAudioSample
	{
		void Serialize(Stream stream);

		Task SerializeAsync(Stream stream, CancellationToken token);
	}
	public interface IPipeSink
	{
		Task ReadAsync(Stream inputStream, CancellationToken cancellationToken);

		string GetFormat();
	}
	public interface IPipeSource
	{
		string GetStreamArguments();

		Task WriteAsync(Stream outputStream, CancellationToken cancellationToken);
	}
	public interface IVideoFrame
	{
		int Width { get; }

		int Height { get; }

		string Format { get; }

		void Serialize(Stream pipe);

		Task SerializeAsync(Stream pipe, CancellationToken token);
	}
	internal static class PipeHelpers
	{
		public static string GetUnqiuePipeName()
		{
			return "FFMpegCore_" + Guid.NewGuid().ToString("N").Substring(0, 5);
		}

		public static string GetPipePath(string pipeName)
		{
			if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
			{
				return "\\\\.\\pipe\\" + pipeName;
			}
			return "unix:" + Path.Combine(Path.GetTempPath(), "CoreFxPipe_" + pipeName);
		}
	}
	public class RawAudioPipeSource : IPipeSource
	{
		private readonly IEnumerator<IAudioSample> _sampleEnumerator;

		public string Format { get; set; } = "s16le";


		public uint SampleRate { get; set; } = 8000u;


		public uint Channels { get; set; } = 1u;


		public RawAudioPipeSource(IEnumerator<IAudioSample> sampleEnumerator)
		{
			_sampleEnumerator = sampleEnumerator;
		}

		public RawAudioPipeSource(IEnumerable<IAudioSample> sampleEnumerator)
			: this(sampleEnumerator.GetEnumerator())
		{
		}

		public string GetStreamArguments()
		{
			return $"-f {Format} -ar {SampleRate} -ac {Channels}";
		}

		public async Task WriteAsync(Stream outputStream, CancellationToken cancellationToken)
		{
			if (_sampleEnumerator.Current != null)
			{
				await _sampleEnumerator.Current.SerializeAsync(outputStream, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			while (_sampleEnumerator.MoveNext())
			{
				await _sampleEnumerator.Current.SerializeAsync(outputStream, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
		}
	}
	public class RawVideoPipeSource : IPipeSource
	{
		private bool _formatInitialized;

		private readonly IEnumerator<IVideoFrame> _framesEnumerator;

		public string StreamFormat { get; private set; }

		public int Width { get; private set; }

		public int Height { get; private set; }

		public double FrameRate { get; set; } = 25.0;


		public RawVideoPipeSource(IEnumerable<IVideoFrame> framesEnumerator)
		{
			_framesEnumerator = framesEnumerator.GetEnumerator();
		}

		public string GetStreamArguments()
		{
			if (!_formatInitialized)
			{
				if (_framesEnumerator.Current == null && !_framesEnumerator.MoveNext())
				{
					throw new InvalidOperationException("Enumerator is empty, unable to get frame");
				}
				StreamFormat = _framesEnumerator.Current.Format;
				Width = _framesEnumerator.Current.Width;
				Height = _framesEnumerator.Current.Height;
				_formatInitialized = true;
			}
			return $"-f rawvideo -r {FrameRate.ToString(CultureInfo.InvariantCulture)} -pix_fmt {StreamFormat} -s {Width}x{Height}";
		}

		public async Task WriteAsync(Stream outputStream, CancellationToken cancellationToken)
		{
			if (_framesEnumerator.Current != null)
			{
				CheckFrameAndThrow(_framesEnumerator.Current);
				await _framesEnumerator.Current.SerializeAsync(outputStream, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
			while (_framesEnumerator.MoveNext())
			{
				CheckFrameAndThrow(_framesEnumerator.Current);
				await _framesEnumerator.Current.SerializeAsync(outputStream, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
			}
		}

		private void CheckFrameAndThrow(IVideoFrame frame)
		{
			if (frame.Width != Width || frame.Height != Height || frame.Format != StreamFormat)
			{
				throw new FFMpegStreamFormatException(FFMpegExceptionType.Operation, "Video frame is not the same format as created raw video stream\r\n" + $"Frame format: {frame.Width}x{frame.Height} pix_fmt: {frame.Format}\r\n" + $"Stream format: {Width}x{Height} pix_fmt: {StreamFormat}");
			}
		}
	}
	public class StreamPipeSink : IPipeSink
	{
		public Func<Stream, CancellationToken, Task> Writer { get; }

		public int BlockSize { get; set; } = 4096;


		public string Format { get; set; } = string.Empty;


		public StreamPipeSink(Func<Stream, CancellationToken, Task> writer)
		{
			Writer = writer;
		}

		public StreamPipeSink(Stream destination)
		{
			Stream destination2 = destination;
			base..ctor();
			StreamPipeSink streamPipeSink = this;
			Writer = (Stream inputStream, CancellationToken cancellationToken) => inputStream.CopyToAsync(destination2, streamPipeSink.BlockSize, cancellationToken);
		}

		public async Task ReadAsync(Stream inputStream, CancellationToken cancellationToken)
		{
			await Writer(inputStream, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}

		public string GetFormat()
		{
			return Format;
		}
	}
	public class StreamPipeSource : IPipeSource
	{
		public Stream Source { get; }

		public int BlockSize { get; } = 4096;


		public string StreamFormat { get; } = string.Empty;


		public StreamPipeSource(Stream source)
		{
			Source = source;
		}

		public string GetStreamArguments()
		{
			return StreamFormat;
		}

		public Task WriteAsync(Stream outputStream, CancellationToken cancellationToken)
		{
			return Source.CopyToAsync(outputStream, BlockSize, cancellationToken);
		}
	}
}
namespace FFMpegCore.Exceptions
{
	public enum FFMpegExceptionType
	{
		Conversion,
		File,
		Operation,
		Process
	}
	public class FFMpegException : Exception
	{
		public FFMpegExceptionType Type { get; }

		public string FFMpegErrorOutput { get; }

		public FFMpegException(FFMpegExceptionType type, string message, Exception? innerException = null, string ffMpegErrorOutput = "")
			: base(message, innerException)
		{
			FFMpegErrorOutput = ffMpegErrorOutput;
			Type = type;
		}

		public FFMpegException(FFMpegExceptionType type, string message, string ffMpegErrorOutput = "")
			: base(message)
		{
			FFMpegErrorOutput = ffMpegErrorOutput;
			Type = type;
		}

		public FFMpegException(FFMpegExceptionType type, string message)
			: base(message)
		{
			FFMpegErrorOutput = string.Empty;
			Type = type;
		}
	}
	public class FFOptionsException : Exception
	{
		public FFOptionsException(string message, Exception? innerException = null)
			: base(message, innerException)
		{
		}
	}
	public class FFMpegArgumentException : Exception
	{
		public FFMpegArgumentException(string? message = null, Exception? innerException = null)
			: base(message, innerException)
		{
		}
	}
	public class FFMpegStreamFormatException : FFMpegException
	{
		public FFMpegStreamFormatException(FFMpegExceptionType type, string message, Exception? innerException = null)
			: base(type, message, innerException)
		{
		}
	}
	public class FFProbeException : Exception
	{
		public FFProbeException(string message, Exception? inner = null)
			: base(message, inner)
		{
		}
	}
	public class FFProbeProcessException : FFProbeException
	{
		public IReadOnlyCollection<string> ProcessErrors { get; }

		public FFProbeProcessException(string message, IReadOnlyCollection<string> processErrors, Exception? inner = null)
			: base(message, inner)
		{
			ProcessErrors = processErrors;
		}
	}
	public class FormatNullException : FFProbeException
	{
		public FormatNullException()
			: base("Format not specified")
		{
		}
	}
}
namespace FFMpegCore.Enums
{
	public enum AudioQuality
	{
		Ultra = 384,
		VeryHigh = 256,
		Good = 192,
		Normal = 128,
		BelowNormal = 96,
		Low = 64
	}
	public enum FeatureStatus
	{
		Unknown,
		NotSupported,
		Supported
	}
	public class Codec
	{
		public class FeatureLevel
		{
			public bool IsExperimental { get; internal set; }

			public FeatureStatus SupportsFrameLevelMultithreading { get; internal set; }

			public FeatureStatus SupportsSliceLevelMultithreading { get; internal set; }

			public FeatureStatus SupportsDrawHorizBand { get; internal set; }

			public FeatureStatus SupportsDirectRendering { get; internal set; }

			internal void Merge(FeatureLevel other)
			{
				IsExperimental |= other.IsExperimental;
				SupportsFrameLevelMultithreading = (FeatureStatus)Math.Max((int)SupportsFrameLevelMultithreading, (int)other.SupportsFrameLevelMultithreading);
				SupportsSliceLevelMultithreading = (FeatureStatus)Math.Max((int)SupportsSliceLevelMultithreading, (int)other.SupportsSliceLevelMultithreading);
				SupportsDrawHorizBand = (FeatureStatus)Math.Max((int)SupportsDrawHorizBand, (int)other.SupportsDrawHorizBand);
				SupportsDirectRendering = (FeatureStatus)Math.Max((int)SupportsDirectRendering, (int)other.SupportsDirectRendering);
			}
		}

		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+(.+)");

		public string Name { get; private set; }

		public CodecType Type { get; private set; }

		public bool DecodingSupported { get; private set; }

		public bool EncodingSupported { get; private set; }

		public bool IsIntraFrameOnly { get; private set; }

		public bool IsLossy { get; private set; }

		public bool IsLossless { get; private set; }

		public string Description { get; private set; }

		public FeatureLevel EncoderFeatureLevel { get; private set; }

		public FeatureLevel DecoderFeatureLevel { get; private set; }

		internal Codec(string name, CodecType type)
		{
			EncoderFeatureLevel = new FeatureLevel();
			DecoderFeatureLevel = new FeatureLevel();
			Name = name;
			Type = type;
		}

		internal static bool TryParseFromCodecs(string line, out Codec codec)
		{
			Match match = _codecsFormatRegex.Match(line);
			if (!match.Success)
			{
				codec = null;
				return false;
			}
			string value = match.Groups[7].Value;
			CodecType codecType = match.Groups[3].Value switch
			{
				"V" => CodecType.Video, 
				"A" => CodecType.Audio, 
				"D" => CodecType.Data, 
				"S" => CodecType.Subtitle, 
				_ => CodecType.Unknown, 
			};
			if (codecType == CodecType.Unknown)
			{
				codec = null;
				return false;
			}
			codec = new Codec(value, codecType);
			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;
			return true;
		}

		internal static bool TryParseFromEncodersDecoders(string line, out Codec codec, bool isEncoder)
		{
			Match match = _decodersEncodersFormatRegex.Match(line);
			if (!match.Success)
			{
				codec = null;
				return false;
			}
			string value = match.Groups[7].Value;
			CodecType codecType = match.Groups[1].Value switch
			{
				"V" => CodecType.Video, 
				"A" => CodecType.Audio, 
				"D" => CodecType.Data, 
				"S" => CodecType.Subtitle, 
				_ => CodecType.Unknown, 
			};
			if (codecType == CodecType.Unknown)
			{
				codec = null;
				return false;
			}
			codec = new Codec(value, codecType);
			FeatureLevel obj = (isEncoder ? codec.EncoderFeatureLevel : codec.DecoderFeatureLevel);
			codec.DecodingSupported = !isEncoder;
			codec.EncodingSupported = isEncoder;
			obj.SupportsFrameLevelMultithreading = ((!(match.Groups[2].Value != ".")) ? FeatureStatus.NotSupported : FeatureStatus.Supported);
			obj.SupportsSliceLevelMultithreading = ((!(match.Groups[3].Value != ".")) ? FeatureStatus.NotSupported : FeatureStatus.Supported);
			obj.IsExperimental = match.Groups[4].Value != ".";
			obj.SupportsDrawHorizBand = ((!(match.Groups[5].Value != ".")) ? FeatureStatus.NotSupported : FeatureStatus.Supported);
			obj.SupportsDirectRendering = ((!(match.Groups[6].Value != ".")) ? FeatureStatus.NotSupported : FeatureStatus.Supported);
			codec.Description = match.Groups[8].Value;
			return true;
		}

		internal void Merge(Codec other)
		{
			if (Name != other.Name)
			{
				throw new FFMpegException(FFMpegExceptionType.Operation, "different codecs enable to merge");
			}
			Type |= other.Type;
			DecodingSupported |= other.DecodingSupported;
			EncodingSupported |= other.EncodingSupported;
			IsIntraFrameOnly |= other.IsIntraFrameOnly;
			IsLossy |= other.IsLossy;
			IsLossless |= other.IsLossless;
			EncoderFeatureLevel.Merge(other.EncoderFeatureLevel);
			DecoderFeatureLevel.Merge(other.DecoderFeatureLevel);
			if (Description != other.Description)
			{
				Description = Description + "\r\n" + other.Description;
			}
		}
	}
	public class ContainerFormat
	{
		private static readonly Regex FormatRegex = new Regex("([D ])([E ])\\s+([a-z0-9_]+)\\s+(.+)");

		public string Name { get; private set; }

		public bool DemuxingSupported { get; private set; }

		public bool MuxingSupported { get; private set; }

		public string Description { get; private set; }

		public string Extension
		{
			get
			{
				if (GlobalFFOptions.Current.ExtensionOverrides.ContainsKey(Name))
				{
					return GlobalFFOptions.Current.ExtensionOverrides[Name];
				}
				return "." + Name;
			}
		}

		internal ContainerFormat(string name)
		{
			Name = name;
		}

		internal static bool TryParse(string line, out ContainerFormat fmt)
		{
			Match match = FormatRegex.Match(line);
			if (!match.Success)
			{
				fmt = null;
				return false;
			}
			fmt = new ContainerFormat(match.Groups[3].Value)
			{
				DemuxingSupported = (match.Groups[1].Value != " "),
				MuxingSupported = (match.Groups[2].Value != " "),
				Description = match.Groups[4].Value
			};
			return true;
		}
	}
	public enum CodecType
	{
		Unknown = 0,
		Video = 2,
		Audio = 4,
		Subtitle = 8,
		Data = 0x10
	}
	public static class VideoCodec
	{
		public static Codec LibX264 => FFMpeg.GetCodec("libx264");

		public static Codec LibX265 => FFMpeg.GetCodec("libx265");

		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.GetContainerFormat("mpegts");

		public static ContainerFormat Ts => FFMpeg.GetContainerFormat("mpegts");

		public static ContainerFormat Mp4 => FFMpeg.GetContainerFormat("mp4");

		public static ContainerFormat Mov => FFMpeg.GetContainerFormat("mov");

		public static ContainerFormat Avi => FFMpeg.GetContainerFormat("avi");

		public static ContainerFormat Ogv => FFMpeg.GetContainerFormat("ogv");

		public static ContainerFormat WebM => FFMpeg.GetContainerFormat("webm");
	}
	public enum Filter
	{
		H264_Mp4ToAnnexB,
		Aac_AdtstoAsc
	}
	public enum Channel
	{
		Audio,
		Video,
		Both,
		VideoNoAttachedPic,
		Subtitle,
		Data,
		Attachments,
		All
	}
	internal static class ChannelMethods
	{
		public static string StreamType(this Channel channel)
		{
			return channel switch
			{
				Channel.Audio => ":a", 
				Channel.Video => ":v", 
				Channel.VideoNoAttachedPic => ":V", 
				Channel.Subtitle => ":s", 
				Channel.Data => ":d", 
				Channel.Attachments => ":t", 
				_ => string.Empty, 
			};
		}
	}
	public enum FFMpegLogLevel
	{
		Quiet,
		Panic,
		Fatal,
		Error,
		Warning,
		Info,
		Verbose,
		Debug,
		Trace
	}
	public static class FileExtension
	{
		public static readonly string Mp4 = VideoType.Mp4.Extension;

		public static readonly string Ts = VideoType.MpegTs.Extension;

		public static readonly string Ogv = VideoType.Ogv.Extension;

		public static readonly string WebM = VideoType.WebM.Extension;

		public static readonly string Png = ".png";

		public static readonly string Mp3 = ".mp3";

		public static readonly string Gif = ".gif";

		public static string Extension(this Codec type)
		{
			return type.Name switch
			{
				"libx264" => Mp4, 
				"libxvpx" => WebM, 
				"libxtheora" => Ogv, 
				"mpegts" => Ts, 
				"png" => Png, 
				_ => throw new Exception("The extension for this video type is not defined."), 
			};
		}
	}
	public enum HardwareAccelerationDevice
	{
		Auto,
		D3D11VA,
		DXVA2,
		QSV,
		CUVID,
		CUDA,
		VDPAU,
		VAAPI,
		LibMFX
	}
	public enum Mirroring
	{
		Vertical,
		Horizontal
	}
	public class PixelFormat
	{
		private static readonly Regex _formatRegex = new Regex("([I\\.])([O\\.])([H\\.])([P\\.])([B\\.])\\s+(\\S+)\\s+([0-9]+)\\s+([0-9]+)");

		public bool InputConversionSupported { get; private set; }

		public bool OutputConversionSupported { get; private set; }

		public bool HardwareAccelerationSupported { get; private set; }

		public bool IsPaletted { get; private set; }

		public bool IsBitstream { get; private set; }

		public string Name { get; private set; }

		public int Components { get; private set; }

		public int BitsPerPixel { get; private set; }

		public bool CanConvertTo(PixelFormat other)
		{
			if (InputConversionSupported)
			{
				return other.OutputConversionSupported;
			}
			return false;
		}

		internal PixelFormat(string name)
		{
			Name = name;
		}

		internal static bool TryParse(string line, out PixelFormat fmt)
		{
			Match match = _formatRegex.Match(line);
			if (!match.Success)
			{
				fmt = null;
				return false;
			}
			fmt = new PixelFormat(match.Groups[6].Value);
			fmt.InputConversionSupported = match.Groups[1].Value != ".";
			fmt.OutputConversionSupported = match.Groups[2].Value != ".";
			fmt.HardwareAccelerationSupported = match.Groups[3].Value != ".";
			fmt.IsPaletted = match.Groups[4].Value != ".";
			fmt.IsBitstream = match.Groups[5].Value != ".";
			if (!int.TryParse(match.Groups[7].Value, out var result))
			{
				return false;
			}
			fmt.Components = result;
			if (!int.TryParse(match.Groups[8].Value, out var result2))
			{
				return false;
			}
			fmt.BitsPerPixel = result2;
			return true;
		}
	}
	public enum Speed
	{
		VerySlow,
		Slower,
		Slow,
		Medium,
		Fast,
		Faster,
		VeryFast,
		SuperFast,
		UltraFast
	}
	public enum Transposition
	{
		CounterClockwise90VerticalFlip,
		Clockwise90,
		CounterClockwise90,
		Clockwise90VerticalFlip
	}
	public enum VideoSize
	{
		FullHd = 1080,
		Hd = 720,
		Ed = 480,
		Ld = 360,
		Original = -1
	}
}
namespace FFMpegCore.Builders.MetaData
{
	public class ChapterData
	{
		public string Title { get; private set; }

		public TimeSpan Start { get; private set; }

		public TimeSpan End { get; private set; }

		public ChapterData(string title, TimeSpan start, TimeSpan end)
		{
			Title = title;
			Start = start;
			End = end;
		}
	}
	public interface IReadOnlyMetaData
	{
		IReadOnlyList<ChapterData> Chapters { get; }

		IReadOnlyDictionary<string, string> Entries { get; }
	}
	public class MetaData : IReadOnlyMetaData
	{
		public Dictionary<string, string> Entries { get; private set; }

		public List<ChapterData> Chapters { get; private set; }

		IReadOnlyList<ChapterData> IReadOnlyMetaData.Chapters => Chapters;

		IReadOnlyDictionary<string, string> IReadOnlyMetaData.Entries => Entries;

		public MetaData()
		{
			Entries = new Dictionary<string, string>();
			Chapters = new List<ChapterData>();
		}

		public MetaData(MetaData cloneSource)
		{
			Entries = new Dictionary<string, string>(cloneSource.Entries);
			Chapters = cloneSource.Chapters.Select(delegate(ChapterData x)
			{
				TimeSpan start = x.Start;
				TimeSpan end = x.End;
				return new ChapterData(x.Title, start, end);
			}).ToList();
		}
	}
	public class MetaDataBuilder
	{
		private readonly MetaData _metaData = new MetaData();

		public MetaDataBuilder WithEntry(string key, string entry)
		{
			if (_metaData.Entries.TryGetValue(key, out string value) && !string.IsNullOrWhiteSpace(value))
			{
				entry = value + "; " + entry;
			}
			_metaData.Entries[key] = entry;
			return this;
		}

		public MetaDataBuilder WithEntry(string key, params string[] values)
		{
			return WithEntry(key, string.Join("; ", values));
		}

		public MetaDataBuilder WithEntry(string key, IEnumerable<string> values)
		{
			return WithEntry(key, string.Join("; ", values));
		}

		public MetaDataBuilder AddChapter(ChapterData chapterData)
		{
			_metaData.Chapters.Add(chapterData);
			return this;
		}

		public MetaDataBuilder AddChapters<T>(IEnumerable<T> values, Func<T, (TimeSpan duration, string title)> chapterGetter)
		{
			foreach (T value in values)
			{
				var (duration, title) = chapterGetter(value);
				AddChapter(duration, title);
			}
			return this;
		}

		public MetaDataBuilder AddChapter(TimeSpan duration, string? title = null)
		{
			TimeSpan timeSpan = _metaData.Chapters.LastOrDefault()?.End ?? TimeSpan.Zero;
			TimeSpan timeSpan2 = timeSpan + duration;
			title = (string.IsNullOrEmpty(title) ? $"Chapter {_metaData.Chapters.Count + 1}" : title);
			_metaData.Chapters.Add(new ChapterData(start: timeSpan, end: timeSpan2, title: title ?? string.Empty));
			return this;
		}

		public MetaDataBuilder WithMajorBrand(string value)
		{
			return WithEntry("major_brand", value);
		}

		public MetaDataBuilder WithMinorVersion(string value)
		{
			return WithEntry("minor_version", value);
		}

		public MetaDataBuilder WithCompatibleBrands(string value)
		{
			return WithEntry("compatible_brands", value);
		}

		public MetaDataBuilder WithCopyright(string value)
		{
			return WithEntry("copyright", value);
		}

		public MetaDataBuilder WithTitle(string value)
		{
			return WithEntry("