| 
					
				 | 
			
			
				@@ -89,6 +89,16 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { "truehd", 6 }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public static readonly string[] LosslessAudioCodecs = new string[] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "alac", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "ape", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "flac", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "mlp", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "truehd", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "wavpack" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public EncodingHelper( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IApplicationPaths appPaths, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             IMediaEncoder mediaEncoder, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -128,14 +138,10 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if (!string.IsNullOrEmpty(hwType) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     && encodingOptions.EnableHardwareEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    && codecMap.ContainsKey(hwType)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    && codecMap.TryGetValue(hwType, out var preferredEncoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    && _mediaEncoder.SupportsEncoder(preferredEncoder)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var preferredEncoder = codecMap[hwType]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (_mediaEncoder.SupportsEncoder(preferredEncoder)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        return preferredEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return preferredEncoder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -551,7 +557,8 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return Array.FindIndex(_videoProfilesH264, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (string.Equals("hevc", videoCodec, StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals("hevc", videoCodec, StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return Array.FindIndex(_videoProfilesH265, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -620,6 +627,11 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return "flac"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(codec, "dts", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return "dca"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return codec.ToLowerInvariant(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -827,39 +839,38 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var filterDevArgs = GetFilterHwDeviceArgs(VaapiAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var doOclTonemap = isHwTonemapAvailable && IsOpenclFullSupported(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (isHwTonemapAvailable && IsOpenclFullSupported()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (_mediaEncoder.IsVaapiDeviceInteliHD || _mediaEncoder.IsVaapiDeviceInteli965) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if (_mediaEncoder.IsVaapiDeviceInteliHD || _mediaEncoder.IsVaapiDeviceInteli965) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (doOclTonemap && !isVaapiDecoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        if (!isVaapiDecoder) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            args.Append(GetOpenclDeviceArgs(0, null, VaapiAlias, OpenclAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        args.Append(GetOpenclDeviceArgs(0, null, VaapiAlias, OpenclAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    else if (_mediaEncoder.IsVaapiDeviceAmd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else if (_mediaEncoder.IsVaapiDeviceAmd) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (IsVulkanFullSupported() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        && _mediaEncoder.IsVaapiDeviceSupportVulkanFmtModifier 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        && Environment.OSVersion.Version >= _minKernelVersionAmdVkFmtModifier) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        if (!IsVulkanFullSupported() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            || !_mediaEncoder.IsVaapiDeviceSupportVulkanFmtModifier 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            || Environment.OSVersion.Version < _minKernelVersionAmdVkFmtModifier) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            args.Append(GetOpenclDeviceArgs(0, "Advanced Micro Devices", null, OpenclAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            // libplacebo wants an explicitly set vulkan filter device. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            args.Append(GetVulkanDeviceArgs(0, null, VaapiAlias, VulkanAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            filterDevArgs = GetFilterHwDeviceArgs(VulkanAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        // libplacebo wants an explicitly set vulkan filter device. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        args.Append(GetVulkanDeviceArgs(0, null, VaapiAlias, VulkanAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        filterDevArgs = GetFilterHwDeviceArgs(VulkanAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    else if (doOclTonemap) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        args.Append(GetOpenclDeviceArgs(0, null, null, OpenclAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        // ROCm/ROCr OpenCL runtime 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        args.Append(GetOpenclDeviceArgs(0, "Advanced Micro Devices", null, OpenclAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else if (doOclTonemap) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    args.Append(GetOpenclDeviceArgs(0, null, null, OpenclAlias)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    filterDevArgs = GetFilterHwDeviceArgs(OpenclAlias); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 args.Append(filterDevArgs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1099,19 +1110,19 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return "-bsf:v h264_mp4toannexb"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (IsH265(stream)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (IsH265(stream)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return "-bsf:v hevc_mp4toannexb"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (IsAAC(stream)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (IsAAC(stream)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // Convert adts header(mpegts) to asc header(mp4). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return "-bsf:a aac_adtstoasc"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public static string GetAudioBitStreamArguments(EncodingJobInfo state, string segmentContainer, string mediaSourceContainer) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1189,10 +1200,8 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return FormattableString.Invariant($" -rc_mode CBR -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return FormattableString.Invariant($" -rc_mode VBR -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return FormattableString.Invariant($" -rc_mode VBR -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return FormattableString.Invariant($" -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1406,7 +1415,7 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var param = string.Empty; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Tutorials: Enable Intel GuC / HuC firmware loading for Low Power Encoding. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // https://01.org/linuxgraphics/downloads/firmware 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // https://01.org/group/43/downloads/firmware 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // https://wiki.archlinux.org/title/intel_graphics#Enable_GuC_/_HuC_firmware_loading 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Intel Low Power Encoding can save unnecessary CPU-GPU synchronization, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // which will reduce overhead in performance intensive tasks such as 4k transcoding and tonemapping. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2050,9 +2059,9 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Video bitrate must fall within requested value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Audio bitrate must fall within requested value 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (request.AudioBitRate.HasValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                && audioStream.BitDepth.HasValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                && audioStream.BitRate.HasValue 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 && audioStream.BitRate.Value > request.AudioBitRate.Value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return false; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2139,7 +2148,7 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var outputScaleFactor = GetVideoBitrateScaleFactor(outputVideoCodec); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // Don't scale the real bitrate lower than the requested bitrate 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var scaleFactor = Math.Min(outputScaleFactor / inputScaleFactor, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var scaleFactor = Math.Max(outputScaleFactor / inputScaleFactor, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (bitrate <= 500000) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2161,56 +2170,96 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return Convert.ToInt32(scaleFactor * bitrate); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int? GetAudioBitrateParam(BaseEncodingJobOptions request, MediaStream audioStream, int? outputAudioChannels) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec, audioStream); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return GetAudioBitrateParam(request.AudioBitRate, request.AudioCodec, audioStream, outputAudioChannels); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, MediaStream audioStream) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public int? GetAudioBitrateParam(int? audioBitRate, string audioCodec, MediaStream audioStream, int? outputAudioChannels) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (audioStream is null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (audioBitRate.HasValue && string.IsNullOrEmpty(audioCodec)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var inputChannels = audioStream.Channels ?? 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var outputChannels = outputAudioChannels ?? 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var bitrate = audioBitRate ?? int.MaxValue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.IsNullOrEmpty(audioCodec) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || string.Equals(audioCodec, "opus", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || string.Equals(audioCodec, "vorbis", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return Math.Min(384000, audioBitRate.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return (inputChannels, outputChannels) switch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (>= 6, >= 6 or 0) => Math.Min(640000, bitrate), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (> 0, > 0) => Math.Min(outputChannels * 128000, bitrate), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (> 0, _) => Math.Min(inputChannels * 128000, bitrate), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (_, _) => Math.Min(384000, bitrate) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (audioBitRate.HasValue && !string.IsNullOrEmpty(audioCodec)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                || string.Equals(audioCodec, "dca", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    || string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    || string.Equals(audioCodec, "opus", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    || string.Equals(audioCodec, "vorbis", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    || string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    || string.Equals(audioCodec, "eac3", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return (inputChannels, outputChannels) switch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if ((audioStream.Channels ?? 0) >= 6) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        return Math.Min(640000, audioBitRate.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (>= 6, >= 6 or 0) => Math.Min(768000, bitrate), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (> 0, > 0) => Math.Min(outputChannels * 136000, bitrate), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (> 0, _) => Math.Min(inputChannels * 136000, bitrate), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    (_, _) => Math.Min(672000, bitrate) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return Math.Min(384000, audioBitRate.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Empty bitrate area is not allow on iOS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // Default audio bitrate to 128K per channel if we don't have codec specific defaults 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return 128000 * (outputAudioChannels ?? audioStream.Channels ?? 2); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                if (string.Equals(audioCodec, "flac", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    || string.Equals(audioCodec, "alac", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        public string GetAudioVbrModeParam(string encoder, int bitratePerChannel) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(encoder, "libfdk_aac", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return " -vbr:a " + bitratePerChannel switch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    if ((audioStream.Channels ?? 0) >= 6) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        return Math.Min(3584000, audioBitRate.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 32000 => "1", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 48000 => "2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 64000 => "3", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 96000 => "4", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _ => "5" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return Math.Min(1536000, audioBitRate.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(encoder, "libmp3lame", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return " -qscale:a " + bitratePerChannel switch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 48000 => "8", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 64000 => "6", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 88000 => "4", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 112000 => "2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _ => "0" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Empty bitrate area is not allow on iOS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Default audio bitrate to 128K if it is not being requested 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // https://ffmpeg.org/ffmpeg-codecs.html#toc-Codec-Options 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return 128000; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(encoder, "libvorbis", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return " -qscale:a " + bitratePerChannel switch 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 40000 => "0", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 56000 => "2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 80000 => "4", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    < 112000 => "6", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    _ => "8" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         public string GetAudioFilterParam(EncodingJobInfo state, EncodingOptions encodingOptions) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2564,8 +2613,8 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (outputWidth > maximumWidth || outputHeight > maximumHeight) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var scaleW = (double)maximumWidth / (double)outputWidth; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                var scaleH = (double)maximumHeight / (double)outputHeight; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var scaleW = (double)maximumWidth / outputWidth; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var scaleH = (double)maximumHeight / outputHeight; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var scale = Math.Min(scaleW, scaleH); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 outputWidth = Math.Min(maximumWidth, (int)(outputWidth * scale)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 outputHeight = Math.Min(maximumHeight, (int)(outputHeight * scale)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2712,79 +2761,76 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             widthParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             heightParam); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return GetFixedSwScaleFilter(threedFormat, requestedWidth.Value, requestedHeight.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return GetFixedSwScaleFilter(threedFormat, requestedWidth.Value, requestedHeight.Value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // If Max dimensions were supplied, for width selects lowest even number between input width and width req size and selects lowest even number from in width*display aspect and requested size 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (requestedMaxWidth.HasValue && requestedMaxHeight.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (requestedMaxWidth.HasValue && requestedMaxHeight.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var maxWidthParam = requestedMaxWidth.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var maxHeightParam = requestedMaxHeight.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        "scale=trunc(min(max(iw\\,ih*a)\\,min({0}\\,{1}*a))/{2})*{2}:trunc(min(max(iw/a\\,ih)\\,min({0}/a\\,{1}))/2)*2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        maxWidthParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        maxHeightParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "scale=trunc(min(max(iw\\,ih*a)\\,min({0}\\,{1}*a))/{2})*{2}:trunc(min(max(iw/a\\,ih)\\,min({0}/a\\,{1}))/2)*2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    maxWidthParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    maxHeightParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // If a fixed width was requested 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (requestedWidth.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (requestedWidth.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if (threedFormat.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     // This method can handle 0 being passed in for the requested height 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return GetFixedSwScaleFilter(threedFormat, requestedWidth.Value, 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    var widthParam = requestedWidth.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            "scale={0}:trunc(ow/a/2)*2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                            widthParam); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var widthParam = requestedWidth.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "scale={0}:trunc(ow/a/2)*2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    widthParam); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // If a fixed height was requested 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (requestedHeight.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (requestedHeight.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var heightParam = requestedHeight.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        "scale=trunc(oh*a/{1})*{1}:{0}", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        heightParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "scale=trunc(oh*a/{1})*{1}:{0}", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    heightParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // If a max width was requested 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (requestedMaxWidth.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (requestedMaxWidth.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var maxWidthParam = requestedMaxWidth.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        "scale=trunc(min(max(iw\\,ih*a)\\,{0})/{1})*{1}:trunc(ow/a/2)*2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        maxWidthParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "scale=trunc(min(max(iw\\,ih*a)\\,{0})/{1})*{1}:trunc(ow/a/2)*2", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    maxWidthParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             // If a max height was requested 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (requestedMaxHeight.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (requestedMaxHeight.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var maxHeightParam = requestedMaxHeight.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        "scale=trunc(oh*a/{1})*{1}:min(max(iw/a\\,ih)\\,{0})", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        maxHeightParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "scale=trunc(oh*a/{1})*{1}:min(max(iw/a\\,ih)\\,{0})", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    maxHeightParam, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    scaleVal); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return string.Empty; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2858,18 +2904,21 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     "yadif_cuda={0}:-1:0", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     doubleRateDeint ? "1" : "0"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (hwDeintSuffix.Contains("vaapi", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (hwDeintSuffix.Contains("vaapi", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     CultureInfo.InvariantCulture, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     "deinterlace_vaapi=rate={0}", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     doubleRateDeint ? "field" : "frame"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (hwDeintSuffix.Contains("qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (hwDeintSuffix.Contains("qsv", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return "deinterlace_qsv=mode=2"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (hwDeintSuffix.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (hwDeintSuffix.Contains("videotoolbox", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return string.Format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     CultureInfo.InvariantCulture, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -2900,7 +2949,8 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         options.VppTonemappingBrightness, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         options.VppTonemappingContrast); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (string.Equals(hwTonemapSuffix, "vulkan", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (string.Equals(hwTonemapSuffix, "vulkan", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 args = "libplacebo=format={1}:tonemapping={2}:color_primaries=bt709:color_trc=bt709:colorspace=bt709:peak_detect=0:upscaler=none:downscaler=none"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -4214,7 +4264,8 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // sw => hw 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 if (doVkTonemap) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    mainFilters.Add("hwupload_vaapi"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    mainFilters.Add("hwupload=derive_device=vaapi"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    mainFilters.Add("format=vaapi"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     mainFilters.Add("hwmap=derive_device=vulkan"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     mainFilters.Add("format=vulkan"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -4325,12 +4376,15 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     // prefer vaapi hwupload to vulkan hwupload, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     // Mesa RADV does not support a dedicated transfer queue. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    subFilters.Add("hwupload_vaapi"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    subFilters.Add("hwupload=derive_device=vaapi"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    subFilters.Add("format=vaapi"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     subFilters.Add("hwmap=derive_device=vulkan"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     subFilters.Add("format=vulkan"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     overlayFilters.Add("overlay_vulkan=eof_action=endall:shortest=1:repeatlast=0"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    overlayFilters.Add("scale_vulkan=format=nv12"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // TODO: figure out why libplacebo can sync without vaSyncSurface VPP support in radeonsi. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    overlayFilters.Add("libplacebo=format=nv12:apply_filmgrain=0:apply_dolbyvision=0:upscaler=none:downscaler=none:dithering=none"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     // OUTPUT vaapi(nv12/bgra) surface(vram) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     // reverse-mapping via vaapi-vulkan interop. 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -4772,26 +4826,27 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return videoStream.BitDepth.Value; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else if (string.Equals(videoStream.PixelFormat, "yuv420p", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         || string.Equals(videoStream.PixelFormat, "yuvj420p", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         || string.Equals(videoStream.PixelFormat, "yuv444p", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (string.Equals(videoStream.PixelFormat, "yuv420p", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    || string.Equals(videoStream.PixelFormat, "yuvj420p", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    || string.Equals(videoStream.PixelFormat, "yuv444p", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return 8; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else if (string.Equals(videoStream.PixelFormat, "yuv420p10le", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         || string.Equals(videoStream.PixelFormat, "yuv444p10le", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (string.Equals(videoStream.PixelFormat, "yuv420p10le", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    || string.Equals(videoStream.PixelFormat, "yuv444p10le", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return 10; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else if (string.Equals(videoStream.PixelFormat, "yuv420p12le", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                         || string.Equals(videoStream.PixelFormat, "yuv444p12le", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (string.Equals(videoStream.PixelFormat, "yuv420p12le", StringComparison.OrdinalIgnoreCase) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    || string.Equals(videoStream.PixelFormat, "yuv444p12le", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     return 12; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    return 8; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return 8; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             return 0; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -5023,11 +5078,9 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                             + (nvdecNoInternalCopy ? " -hwaccel_flags +unsafe_output" : string.Empty) + " -threads 1" + (isAv1 ? " -c:v av1" : string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        // cuvid decoder doesn't have threading issue. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                        return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // cuvid decoder doesn't have threading issue. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    return " -hwaccel cuda" + (outputHwSurface ? " -hwaccel_output_format cuda" : string.Empty); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -5385,7 +5438,8 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // Automatically set thread count 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return mustSetThreadCount ? Math.Max(Environment.ProcessorCount - 1, 1) : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            else if (threads >= Environment.ProcessorCount) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (threads >= Environment.ProcessorCount) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return Environment.ProcessorCount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -5670,14 +5724,22 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var inputChannels = audioStream is null ? 6 : audioStream.Channels ?? 6; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var shiftAudioCodecs = new List<string>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (inputChannels >= 6) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // DTS and TrueHD are not supported by HLS 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Keep them in the supported codecs list, but shift them to the end of the list so that if transcoding happens, another codec is used 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                shiftAudioCodecs.Add("dca"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                shiftAudioCodecs.Add("truehd"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Transcoding to 2ch ac3 or eac3 almost always causes a playback failure 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // Keep them in the supported codecs list, but shift them to the end of the list so that if transcoding happens, another codec is used 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                shiftAudioCodecs.Add("ac3"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                shiftAudioCodecs.Add("eac3"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Transcoding to 2ch ac3 almost always causes a playback failure 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            // Keep it in the supported codecs list, but shift it to the end of the list so that if transcoding happens, another codec is used 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            var shiftAudioCodecs = new[] { "ac3", "eac3" }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (audioCodecs.All(i => shiftAudioCodecs.Contains(i, StringComparison.OrdinalIgnoreCase))) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 return; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -5919,10 +5981,17 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var bitrate = state.OutputAudioBitrate; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (bitrate.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (bitrate.HasValue && !LosslessAudioCodecs.Contains(codec, StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var vbrParam = GetAudioVbrModeParam(codec, bitrate.Value / (channels ?? 2)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (encodingOptions.EnableAudioVbr && vbrParam is not null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    args += vbrParam; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    args += " -ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             if (state.OutputAudioSampleRate.HasValue) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -5940,23 +6009,33 @@ namespace MediaBrowser.Controller.MediaEncoding 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var audioTranscodeParams = new List<string>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             var bitrate = state.OutputAudioBitrate; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var channels = state.OutputAudioChannels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            var outputCodec = state.OutputAudioCodec; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (bitrate.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (bitrate.HasValue && !LosslessAudioCodecs.Contains(outputCodec, StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                var vbrParam = GetAudioVbrModeParam(GetAudioEncoder(state), bitrate.Value / (channels ?? 2)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (encodingOptions.EnableAudioVbr && vbrParam is not null) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    audioTranscodeParams.Add(vbrParam); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                else 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    audioTranscodeParams.Add("-ab " + bitrate.Value.ToString(CultureInfo.InvariantCulture)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (state.OutputAudioChannels.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (channels.HasValue) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 audioTranscodeParams.Add("-ac " + state.OutputAudioChannels.Value.ToString(CultureInfo.InvariantCulture)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!string.IsNullOrEmpty(state.OutputAudioCodec)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!string.IsNullOrEmpty(outputCodec)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 audioTranscodeParams.Add("-acodec " + GetAudioEncoder(state)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            if (!string.Equals(state.OutputAudioCodec, "opus", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (!string.Equals(outputCodec, "opus", StringComparison.OrdinalIgnoreCase)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 // opus only supports specific sampling rates 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 var sampleRate = state.OutputAudioSampleRate; 
			 |