| 
					
				 | 
			
			
				@@ -3,17 +3,14 @@ using System.Collections.Generic; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Globalization; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Linq; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using System.Text.RegularExpressions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Threading; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using System.Threading.Tasks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Common.Configuration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Common.Extensions; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using MediaBrowser.Common.Net; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using MediaBrowser.Controller.Channels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.Configuration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.Library; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using MediaBrowser.Controller.LiveTv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Controller.MediaEncoding; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-using MediaBrowser.Controller.Session; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.MediaEncoding.Probing; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.Configuration; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.Diagnostics; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -22,6 +19,7 @@ using MediaBrowser.Model.Entities; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.IO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.MediaInfo; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using MediaBrowser.Model.Serialization; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+using MediaBrowser.Model.System; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 using Microsoft.Extensions.Logging; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 namespace MediaBrowser.MediaEncoding.Encoder 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -32,340 +30,223 @@ namespace MediaBrowser.MediaEncoding.Encoder 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     public class MediaEncoder : IMediaEncoder, IDisposable 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// The _logger 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly ILogger _logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// Gets the json serializer. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Gets the encoder path. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <value>The json serializer.</value> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly IJsonSerializer _jsonSerializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <value>The encoder path.</value> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public string EncoderPath => FFmpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// The _thumbnail resource pool 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// The location of the discovered FFmpeg tool. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(1, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public string FFMpegPath { get; private set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public string FFProbePath { get; private set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public FFmpegLocation EncoderLocation { get; private set; } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly ILogger _logger; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly IJsonSerializer _jsonSerializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private string FFmpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private string FFprobePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         protected readonly IServerConfigurationManager ConfigurationManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         protected readonly IFileSystem FileSystem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        protected readonly ILiveTvManager LiveTvManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        protected readonly IIsoManager IsoManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        protected readonly ILibraryManager LibraryManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        protected readonly IChannelManager ChannelManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        protected readonly ISessionManager SessionManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         protected readonly Func<ISubtitleEncoder> SubtitleEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         protected readonly Func<IMediaSourceManager> MediaSourceManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly IHttpClient _httpClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly IZipClient _zipClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly IProcessFactory _processFactory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly int DefaultImageExtractionTimeoutMs; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly string StartupOptionFFmpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly string StartupOptionFFprobePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private readonly SemaphoreSlim _thumbnailResourcePool = new SemaphoreSlim(1, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private readonly List<ProcessWrapper> _runningProcesses = new List<ProcessWrapper>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly bool _hasExternalEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly string _originalFFMpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly string _originalFFProbePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private readonly int DefaultImageExtractionTimeoutMs; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public MediaEncoder( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ILoggerFactory loggerFactory, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IJsonSerializer jsonSerializer, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            string ffMpegPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            string ffProbePath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            bool hasExternalEncoder, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            string startupOptionsFFmpegPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            string startupOptionsFFprobePath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IServerConfigurationManager configurationManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IFileSystem fileSystem, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ILiveTvManager liveTvManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            IIsoManager isoManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ILibraryManager libraryManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            IChannelManager channelManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ISessionManager sessionManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             Func<ISubtitleEncoder> subtitleEncoder, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             Func<IMediaSourceManager> mediaSourceManager, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            IHttpClient httpClient, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            IZipClient zipClient, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IProcessFactory processFactory, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             int defaultImageExtractionTimeoutMs) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _logger = loggerFactory.CreateLogger(nameof(MediaEncoder)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _jsonSerializer = jsonSerializer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            StartupOptionFFmpegPath = startupOptionsFFmpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            StartupOptionFFprobePath = startupOptionsFFprobePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ConfigurationManager = configurationManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             FileSystem = fileSystem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            LiveTvManager = liveTvManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            IsoManager = isoManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            LibraryManager = libraryManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ChannelManager = channelManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            SessionManager = sessionManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             SubtitleEncoder = subtitleEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            MediaSourceManager = mediaSourceManager; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _httpClient = httpClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _zipClient = zipClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _processFactory = processFactory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             DefaultImageExtractionTimeoutMs = defaultImageExtractionTimeoutMs; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            FFProbePath = ffProbePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            FFMpegPath = ffMpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _originalFFProbePath = ffProbePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _originalFFMpegPath = ffMpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _hasExternalEncoder = hasExternalEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public string EncoderLocationType 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Run at startup or if the user removes a Custom path from transcode page. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Sets global variables FFmpegPath. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Precedence is: Config > CLI > $PATH 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public void SetFFmpegPath() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            get 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // ToDo - Finalise removal of the --ffprobe switch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!string.IsNullOrEmpty(StartupOptionFFprobePath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (_hasExternalEncoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return "External"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (string.IsNullOrWhiteSpace(FFMpegPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (IsSystemInstalledPath(FFMpegPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return "System"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return "Custom"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                _logger.LogWarning("--ffprobe switch is deprecated and shall be removed in the next release"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private bool IsSystemInstalledPath(string path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (path.IndexOf("/", StringComparison.Ordinal) == -1 && path.IndexOf("\\", StringComparison.Ordinal) == -1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 1) Custom path stored in config/encoding xml file under tag <EncoderAppPath> takes precedence 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!ValidatePath(ConfigurationManager.GetConfiguration<EncodingOptions>("encoding").EncoderAppPath, FFmpegLocation.Custom)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 2) Check if the --ffmpeg CLI switch has been given 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!ValidatePath(StartupOptionFFmpegPath, FFmpegLocation.SetByArgument)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 3) Search system $PATH environment variable for valid FFmpeg 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (!ValidatePath(ExistsOnSystemPath("ffmpeg"), FFmpegLocation.System)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        EncoderLocation = FFmpegLocation.NotFound; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        FFmpegPath = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public void Init() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            InitPaths(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Write the FFmpeg path to the config/encoding.xml file as <EncoderAppPathDisplay> so it appears in UI 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var config = ConfigurationManager.GetConfiguration<EncodingOptions>("encoding"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            config.EncoderAppPathDisplay = FFmpegPath ?? string.Empty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ConfigurationManager.SaveConfiguration("encoding", config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!string.IsNullOrWhiteSpace(FFMpegPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Only if mpeg path is set, try and set path to probe 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (FFmpegPath != null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var result = new EncoderValidator(_logger, _processFactory).Validate(FFMpegPath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Determine a probe path from the mpeg path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                FFprobePath = Regex.Replace(FFmpegPath, @"[^\/\\]+?(\.[^\/\\\n.]+)?$", @"ffprobe$1"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Interrogate to understand what coders are supported 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var result = new EncoderValidator(_logger, _processFactory).GetAvailableCoders(FFmpegPath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 SetAvailableDecoders(result.decoders); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 SetAvailableEncoders(result.encoders); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void InitPaths() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            ConfigureEncoderPaths(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_hasExternalEncoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                LogPaths(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // If the path was passed in, save it into config now. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var encodingOptions = GetEncodingOptions(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var appPath = encodingOptions.EncoderAppPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var valueToSave = FFMpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!string.IsNullOrWhiteSpace(valueToSave)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // if using system variable, don't save this. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (IsSystemInstalledPath(valueToSave) || _hasExternalEncoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    valueToSave = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!string.Equals(valueToSave, appPath, StringComparison.Ordinal)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                encodingOptions.EncoderAppPath = valueToSave; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ConfigurationManager.SaveConfiguration("encoding", encodingOptions); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            _logger.LogInformation("FFmpeg: {0}: {1}", EncoderLocation.ToString(), FFmpegPath ?? string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Triggered from the Settings > Transcoding UI page when users submits Custom FFmpeg path to use. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Only write the new path to xml if it exists.  Do not perform validation checks on ffmpeg here. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="path"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="pathType"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public void UpdateEncoderPath(string path, string pathType) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_hasExternalEncoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            string newPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _logger.LogInformation("Attempting to update encoder path to {0}. pathType: {1}", path ?? string.Empty, pathType ?? string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Tuple<string, string> newPaths; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.Equals(pathType, "system", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                path = "ffmpeg"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                newPaths = TestForInstalledVersions(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (string.Equals(pathType, "custom", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!string.Equals(pathType, "custom", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (string.IsNullOrWhiteSpace(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw new ArgumentNullException(nameof(path)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (!File.Exists(path) && !Directory.Exists(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    throw new ResourceNotFoundException(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                newPaths = GetEncoderPaths(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new ArgumentException("Unexpected pathType value"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else if (string.IsNullOrWhiteSpace(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new ArgumentException("Unexpected pathType value"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // User had cleared the custom path in UI 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                newPath = string.Empty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.IsNullOrWhiteSpace(newPaths.Item1)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else if (File.Exists(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new ResourceNotFoundException("ffmpeg not found"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                newPath = path; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.IsNullOrWhiteSpace(newPaths.Item2)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else if (Directory.Exists(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new ResourceNotFoundException("ffprobe not found"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Given path is directory, so resolve down to filename 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                newPath = GetEncoderPathFromDirectory(path, "ffmpeg"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            path = newPaths.Item1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!ValidateVersion(path, true)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                throw new ResourceNotFoundException("ffmpeg version 3.0 or greater is required."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                throw new ResourceNotFoundException(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var config = GetEncodingOptions(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            config.EncoderAppPath = path; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Write the new ffmpeg path to the xml as <EncoderAppPath> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // This ensures its not lost on next startup 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var config = ConfigurationManager.GetConfiguration<EncodingOptions>("encoding"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            config.EncoderAppPath = newPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             ConfigurationManager.SaveConfiguration("encoding", config); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            Init(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Trigger SetFFmpegPath so we validate the new path and setup probe path 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            SetFFmpegPath(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private bool ValidateVersion(string path, bool logOutput) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return new EncoderValidator(_logger, _processFactory).ValidateVersion(path, logOutput); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void ConfigureEncoderPaths() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Validates the supplied FQPN to ensure it is a ffmpeg utility. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// If checks pass, global variable FFmpegPath and EncoderLocation are updated. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="path">FQPN to test</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="location">Location (External, Custom, System) of tool</param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private bool ValidatePath(string path, FFmpegLocation location) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_hasExternalEncoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var appPath = GetEncodingOptions().EncoderAppPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            bool rc = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.IsNullOrWhiteSpace(appPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!string.IsNullOrEmpty(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                appPath = Path.Combine(ConfigurationManager.ApplicationPaths.ProgramDataPath, "ffmpeg"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var newPaths = GetEncoderPaths(appPath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.IsNullOrWhiteSpace(newPaths.Item1) || string.IsNullOrWhiteSpace(newPaths.Item2) || IsSystemInstalledPath(appPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                newPaths = TestForInstalledVersions(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!string.IsNullOrWhiteSpace(newPaths.Item1) && !string.IsNullOrWhiteSpace(newPaths.Item2)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                FFMpegPath = newPaths.Item1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                FFProbePath = newPaths.Item2; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (File.Exists(path)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    rc = new EncoderValidator(_logger, _processFactory).ValidateVersion(path, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            LogPaths(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (!rc) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        _logger.LogWarning("FFmpeg: {0}: Failed version check: {1}", location.ToString(), path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private Tuple<string, string> GetEncoderPaths(string configuredPath) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var appPath = configuredPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // ToDo - Enable the ffmpeg validator.  At the moment any version can be used. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    rc = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!string.IsNullOrWhiteSpace(appPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (Directory.Exists(appPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return GetPathsFromDirectory(appPath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    FFmpegPath = path; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    EncoderLocation = location; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (File.Exists(appPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return new Tuple<string, string>(appPath, GetProbePathFromEncoderPath(appPath)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _logger.LogWarning("FFmpeg: {0}: File not found: {1}", location.ToString(), path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return new Tuple<string, string>(null, null); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return rc; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private Tuple<string, string> TestForInstalledVersions() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private string GetEncoderPathFromDirectory(string path, string filename) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            string encoderPath = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            string probePath = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (_hasExternalEncoder && ValidateVersion(_originalFFMpegPath, true)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            try 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                encoderPath = _originalFFMpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                probePath = _originalFFProbePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var files = FileSystem.GetFilePaths(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.IsNullOrWhiteSpace(encoderPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var excludeExtensions = new[] { ".c" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), filename, StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                    && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            catch (Exception) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (ValidateVersion("ffmpeg", true) && ValidateVersion("ffprobe", false)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    encoderPath = "ffmpeg"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    probePath = "ffprobe"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Trap all exceptions, like DirNotExists, and return null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return new Tuple<string, string>(encoderPath, probePath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private Tuple<string, string> GetPathsFromDirectory(string path) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// Search the system $PATH environment variable looking for given filename. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <param name="fileName"></param> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /// <returns></returns> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        private string ExistsOnSystemPath(string filename) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Since we can't predict the file extension, first try directly within the folder 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // If that doesn't pan out, then do a recursive search 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var files = FileSystem.GetFilePaths(path); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var excludeExtensions = new[] { ".c" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var values = Environment.GetEnvironmentVariable("PATH"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var ffprobePath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.IsNullOrWhiteSpace(ffmpegPath) || !File.Exists(ffmpegPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            foreach (var path in values.Split(Path.PathSeparator)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                files = FileSystem.GetFilePaths(path, true); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ffmpegPath = files.FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffmpeg", StringComparison.OrdinalIgnoreCase) && !excludeExtensions.Contains(Path.GetExtension(i) ?? string.Empty)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var candidatePath = GetEncoderPathFromDirectory(path, filename); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (!string.IsNullOrWhiteSpace(ffmpegPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!string.IsNullOrEmpty(candidatePath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    ffprobePath = GetProbePathFromEncoderPath(ffmpegPath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return candidatePath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return new Tuple<string, string>(ffmpegPath, ffprobePath); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private string GetProbePathFromEncoderPath(string appPath) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return FileSystem.GetFilePaths(Path.GetDirectoryName(appPath)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                .FirstOrDefault(i => string.Equals(Path.GetFileNameWithoutExtension(i), "ffprobe", StringComparison.OrdinalIgnoreCase)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private void LogPaths() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogInformation("FFMpeg: {0}", FFMpegPath ?? "not found"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            _logger.LogInformation("FFProbe: {0}", FFProbePath ?? "not found"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        private EncodingOptions GetEncodingOptions() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return ConfigurationManager.GetConfiguration<EncodingOptions>("encoding"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         private List<string> _encoders = new List<string>(); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -412,12 +293,6 @@ namespace MediaBrowser.MediaEncoding.Encoder 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// Gets the encoder path. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// </summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /// <value>The encoder path.</value> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public string EncoderPath => FFMpegPath; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// <summary> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// Gets the media info. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /// </summary> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -489,7 +364,7 @@ namespace MediaBrowser.MediaEncoding.Encoder 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // Must consume both or ffmpeg may hang due to deadlocks. See comments below. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 RedirectStandardOutput = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                FileName = FFProbePath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                FileName = FFprobePath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 Arguments = string.Format(args, probeSizeArgument, inputPath).Trim(), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 IsHidden = true, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -691,10 +566,11 @@ namespace MediaBrowser.MediaEncoding.Encoder 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateNoWindow = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 UseShellExecute = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                FileName = FFMpegPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                FileName = FFmpegPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 Arguments = args, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 IsHidden = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ErrorDialog = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ErrorDialog = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                EnableRaisingEvents = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _logger.LogDebug("{0} {1}", process.StartInfo.FileName, process.StartInfo.Arguments); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -813,10 +689,11 @@ namespace MediaBrowser.MediaEncoding.Encoder 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CreateNoWindow = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 UseShellExecute = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                FileName = FFMpegPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                FileName = FFmpegPath, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 Arguments = args, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 IsHidden = true, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                ErrorDialog = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ErrorDialog = false, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                EnableRaisingEvents = true 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             _logger.LogInformation(process.StartInfo.FileName + " " + process.StartInfo.Arguments); 
			 |