| 
					
				 | 
			
			
				@@ -467,6 +467,27 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     .Append(' '); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (state.IsVideoRequest  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                && string.Equals(encodingOptions.HardwareAccelerationType, "qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var outputVideoCodec = GetVideoEncoder(state, encodingOptions); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (encodingOptions.EnableHardwareEncoding && outputVideoCodec.Contains("qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (!string.IsNullOrEmpty(videoDecoder) && videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        arg.Append("-hwaccel qsv "); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    }  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    else  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        arg.Append("-init_hw_device qsv=hw -filter_hw_device hw "); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    }	 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                arg.Append(videoDecoder + " "); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             arg.Append("-i ") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 .Append(GetInputPathArgument(state)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1562,6 +1583,7 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var videoSizeParam = string.Empty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Setup subtitle scaling 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (state.VideoStream != null && state.VideoStream.Width.HasValue && state.VideoStream.Height.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 videoSizeParam = string.Format( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1570,7 +1592,11 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     state.VideoStream.Width.Value, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     state.VideoStream.Height.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                videoSizeParam += ":force_original_aspect_ratio=decrease"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                //For QSV, feed it into hardware encoder now 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    videoSizeParam += ",hwupload=extra_hw_frames=64"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var mapPrefix = state.SubtitleStream.IsExternal ? 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1581,9 +1607,31 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 ? 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 : state.SubtitleStream.Index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Setup default filtergraph utilizing FFMpeg overlay() and FFMpeg scale() (see the return of this function for index reference) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase))  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                /* 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    QSV in FFMpeg can now setup hardware overlay for transcodes. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    For software decoding and hardware encoding option, frames must be hwuploaded into hardware 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    with fixed frame size.  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (!string.IsNullOrEmpty(videoDecoder) && videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    retStr = " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}]hwupload=extra_hw_frames=64[v];[v][sub]overlay_qsv=x=(W-w)/2:y=(H-h)/2{3}\""; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                " -filter_complex \"[{0}:{1}]{4}[sub];[0:{2}][sub]overlay{3}\"", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                retStr, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 mapPrefix, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 subtitleStreamIndex, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 state.VideoStream.Index, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1647,31 +1695,34 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 requestedMaxWidth, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 requestedMaxHeight); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if ((string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) || string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 && width.HasValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 && height.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                // Work around vaapi's reduced scaling features 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var scaler = "scale_vaapi"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // Given the input dimensions (inputWidth, inputHeight), determine the output dimensions 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // (outputWidth, outputHeight). The user may request precise output dimensions or maximum 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // output dimensions. Output dimensions are guaranteed to be even. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var outputWidth = width.Value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var outputHeight = height.Value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var vaapi_or_qsv = string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) ? "qsv" : "vaapi"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if (!videoWidth.HasValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     || outputWidth != videoWidth.Value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     || !videoHeight.HasValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     || outputHeight != videoHeight.Value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // Force nv12 pixel format to enable 10-bit to 8-bit colour conversion. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     filters.Add( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            "{0}=w={1}:h={2}", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            scaler, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            "scale_{0}=w={1}:h={2}:format=nv12", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            vaapi_or_qsv, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             outputWidth, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             outputHeight)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    filters.Add(string.Format(CultureInfo.InvariantCulture, "scale_{0}=format=nv12", vaapi_or_qsv)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             else if ((videoDecoder ?? string.Empty).IndexOf("_cuvid", StringComparison.OrdinalIgnoreCase) != -1 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1914,10 +1965,26 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 filters.Add("hwupload"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (state.DeInterlace("h264", true) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                && string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // If we are software decoding, and hardware encoding	   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                && (string.IsNullOrEmpty(videoDecoder) || !videoDecoder.Contains("qsv", StringComparison.OrdinalIgnoreCase))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                filters.Add("format=nv12|qsv"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                filters.Add("hwupload=extra_hw_frames=64"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (state.DeInterlace("h264", true)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (string.Equals(outputVideoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_vaapi")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else if (string.Equals(outputVideoCodec, "h264_qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    filters.Add(string.Format(CultureInfo.InvariantCulture, "deinterlace_qsv")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if ((state.DeInterlace("h264", true) || state.DeInterlace("h265", true) || state.DeInterlace("hevc", true)) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1940,8 +2007,6 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var inputHeight = videoStream?.Height; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var threeDFormat = state.MediaSource.Video3DFormat; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, options); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             filters.AddRange(GetScalingFilters(inputWidth, inputHeight, threeDFormat, videoDecoder, outputVideoCodec, request.Width, request.Height, request.MaxWidth, request.MaxHeight)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var output = string.Empty; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2134,6 +2199,7 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var videoDecoder = GetHardwareAcceleratedVideoDecoder(state, encodingOptions); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (!string.IsNullOrEmpty(videoDecoder)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 inputModifier += " " + videoDecoder; 
			 |